remove CanCreateMixin usage from election

This commit is contained in:
imperosol 2025-03-16 23:19:00 +01:00
parent a74037a7f3
commit 86353dca04
2 changed files with 102 additions and 66 deletions

View File

@ -1,7 +1,10 @@
from datetime import timedelta
import pytest
from django.conf import settings
from django.test import TestCase
from django.test import Client, TestCase
from django.urls import reverse
from django.utils.timezone import now
from model_bakery import baker
from core.baker_recipes import subscriber_user
@ -49,6 +52,27 @@ class TestElectionUpdateView(TestElection):
assert response.status_code == 403
@pytest.mark.django_db
def test_election_create_list_permission(client: Client):
election = baker.make(Election, end_candidature=now() + timedelta(hours=1))
groups = [
Group.objects.get(pk=settings.SITH_GROUP_SUBSCRIBERS_ID),
baker.make(Group),
]
election.candidature_groups.add(groups[0])
election.edit_groups.add(groups[1])
url = reverse("election:create_list", kwargs={"election_id": election.id})
for user in subscriber_user.make(), baker.make(User, groups=[groups[1]]):
client.force_login(user)
assert client.get(url).status_code == 200
# the post is a 200 instead of a 302, because we don't give form data,
# but we don't care as we only test permissions here
assert client.post(url).status_code == 200
client.force_login(baker.make(User))
assert client.get(url).status_code == 403
assert client.post(url).status_code == 403
@pytest.mark.django_db
def test_election_results():
election = baker.make(

View File

@ -1,6 +1,12 @@
from typing import TYPE_CHECKING
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from cryptography.utils import cached_property
from django.conf import settings
from django.contrib.auth.mixins import (
LoginRequiredMixin,
PermissionRequiredMixin,
UserPassesTestMixin,
)
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import QuerySet
@ -9,7 +15,7 @@ from django.urls import reverse, reverse_lazy
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
from core.auth.mixins import CanCreateMixin, CanEditMixin, CanViewMixin
from core.auth.mixins import CanEditMixin, CanViewMixin
from election.forms import (
CandidateForm,
ElectionForm,
@ -94,15 +100,26 @@ class ElectionDetailView(CanViewMixin, DetailView):
# Form view
class VoteFormView(CanCreateMixin, FormView):
class VoteFormView(LoginRequiredMixin, UserPassesTestMixin, FormView):
"""Alows users to vote."""
form_class = VoteForm
template_name = "election/election_detail.jinja"
def dispatch(self, request, *arg, **kwargs):
self.election = get_object_or_404(Election, pk=kwargs["election_id"])
return super().dispatch(request, *arg, **kwargs)
@cached_property
def election(self):
return get_object_or_404(Election, pk=self.kwargs["election_id"])
def test_func(self):
groups = set(self.election.vote_groups.values_list("id", flat=True))
if (
settings.SITH_GROUP_SUBSCRIBERS_ID in groups
and self.request.user.is_subscribed
):
# the subscriber group isn't truly attached to users,
# so it must be dealt with separately
return True
return self.request.user.groups.filter(id__in=groups).exists()
def vote(self, election_data):
with transaction.atomic():
@ -122,20 +139,16 @@ class VoteFormView(CanCreateMixin, FormView):
self.election.voters.add(self.request.user)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["election"] = self.election
kwargs["user"] = self.request.user
return kwargs
return super().get_form_kwargs() | {
"election": self.election,
"user": self.request.user,
}
def form_valid(self, form):
"""Verify that the user is part in a vote group."""
data = form.clean()
res = super(FormView, self).form_valid(form)
for grp_id in self.election.vote_groups.values_list("pk", flat=True):
if self.request.user.is_in_group(pk=grp_id):
self.vote(data)
return res
return res
self.vote(data)
return super().form_valid(form)
def get_success_url(self, **kwargs):
return reverse_lazy("election:detail", kwargs={"election_id": self.election.id})
@ -200,80 +213,79 @@ class ElectionCreateView(PermissionRequiredMixin, CreateView):
return reverse("election:detail", kwargs={"election_id": self.object.id})
class RoleCreateView(CanCreateMixin, CreateView):
class RoleCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = Role
form_class = RoleForm
template_name = "core/create.jinja"
def dispatch(self, request, *arg, **kwargs):
self.election = get_object_or_404(Election, pk=kwargs["election_id"])
@cached_property
def election(self):
return get_object_or_404(Election, pk=self.kwargs["election_id"])
def test_func(self):
if not self.election.is_vote_editable:
raise PermissionDenied
return super().dispatch(request, *arg, **kwargs)
return False
if self.request.user.has_perm("election.add_role"):
return True
groups = set(self.election.edit_groups.values_list("id", flat=True))
if (
settings.SITH_GROUP_SUBSCRIBERS_ID in groups
and self.request.user.is_subscribed
):
# the subscriber group isn't truly attached to users,
# so it must be dealt with separately
return True
return self.request.user.groups.filter(id__in=groups).exists()
def get_initial(self):
init = {}
init["election"] = self.election
return init
def form_valid(self, form):
"""Verify that the user can edit properly."""
obj: Role = form.instance
user: User = self.request.user
if obj.election:
for grp_id in obj.election.edit_groups.values_list("pk", flat=True):
if user.is_in_group(pk=grp_id):
return super(CreateView, self).form_valid(form)
raise PermissionDenied
return {"election": self.election}
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["election_id"] = self.election.id
return kwargs
return super().get_form_kwargs() | {"election_id": self.election.id}
def get_success_url(self, **kwargs):
return reverse_lazy(
"election:detail", kwargs={"election_id": self.object.election.id}
return reverse(
"election:detail", kwargs={"election_id": self.object.election_id}
)
class ElectionListCreateView(CanCreateMixin, CreateView):
class ElectionListCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = ElectionList
form_class = ElectionListForm
template_name = "core/create.jinja"
def dispatch(self, request, *arg, **kwargs):
self.election = get_object_or_404(Election, pk=kwargs["election_id"])
@cached_property
def election(self):
return get_object_or_404(Election, pk=self.kwargs["election_id"])
def test_func(self):
if not self.election.is_vote_editable:
raise PermissionDenied
return super().dispatch(request, *arg, **kwargs)
return False
if self.request.user.has_perm("election.add_electionlist"):
return True
groups = set(
self.election.candidature_groups.values("id")
.union(self.election.edit_groups.values("id"))
.values_list("id", flat=True)
)
if (
settings.SITH_GROUP_SUBSCRIBERS_ID in groups
and self.request.user.is_subscribed
):
# the subscriber group isn't truly attached to users,
# so it must be dealt with separately
return True
return self.request.user.groups.filter(id__in=groups).exists()
def get_initial(self):
init = {}
init["election"] = self.election
return init
return {"election": self.election}
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["election_id"] = self.election.id
return kwargs
def form_valid(self, form):
"""Verify that the user can vote on this election."""
obj: ElectionList = form.instance
user: User = self.request.user
if obj.election:
for grp_id in obj.election.candidature_groups.values_list("pk", flat=True):
if user.is_in_group(pk=grp_id):
return super(CreateView, self).form_valid(form)
for grp_id in obj.election.edit_groups.values_list("pk", flat=True):
if user.is_in_group(pk=grp_id):
return super(CreateView, self).form_valid(form)
raise PermissionDenied
return super().get_form_kwargs() | {"election_id": self.election.id}
def get_success_url(self, **kwargs):
return reverse_lazy(
"election:detail", kwargs={"election_id": self.object.election.id}
return reverse(
"election:detail", kwargs={"election_id": self.object.election_id}
)