From 78f0b29921446dcc3b12a9a89c76205cc64fbd14 Mon Sep 17 00:00:00 2001 From: Finn Stutzenstein Date: Thu, 3 Dec 2020 13:23:31 +0100 Subject: [PATCH] Disallows users, who have delegated their votes to others, to selfvote. It is enforced, that the user who gets the vote right must vote for the right-provder. --- server/openslides/poll/views.py | 18 +++++++++-- .../integration/assignments/test_polls.py | 6 ++-- .../tests/integration/motions/test_polls.py | 30 ++++++++++++++----- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/server/openslides/poll/views.py b/server/openslides/poll/views.py index 9a11416b6..d6f0f0ad9 100644 --- a/server/openslides/poll/views.py +++ b/server/openslides/poll/views.py @@ -255,15 +255,29 @@ class BasePollViewSet(ModelViewSet): Analog: has to have manage permissions Named & Pseudoanonymous: has to be in a poll group and present """ + # if the request user is not the vote user, the delegation must be right if request.user != vote_user and request.user != vote_user.vote_delegated_to: - self.permission_denied(request) + raise ValidationError( + { + "detail": f"You cannot vote for {vote_user.id} since the vote right was not delegated to you." + } + ) + + # If the request user is the vote user, this user must not have any delegation. + # It is not allowed to vote for oneself, if the vote is delegated + if request.user == vote_user and request.user.vote_delegated_to is not None: + raise ValidationError( + {"detail": "You cannot vote since your vote right is delegated."} + ) if poll.type == BasePoll.TYPE_ANALOG: if not self.has_manage_permissions(): self.permission_denied(request) else: if poll.state != BasePoll.STATE_STARTED: - raise ValidationError("You can only vote on a started poll.") + raise ValidationError( + {"detail": "You can only vote on a started poll."} + ) if not request.user.is_present or not in_some_groups( vote_user.id, diff --git a/server/tests/integration/assignments/test_polls.py b/server/tests/integration/assignments/test_polls.py index 2c642f2b9..1bbdfff20 100644 --- a/server/tests/integration/assignments/test_polls.py +++ b/server/tests/integration/assignments/test_polls.py @@ -470,9 +470,9 @@ class CreateAssignmentPoll(TestCase): poll = AssignmentPoll.objects.get() self.assertEqual(poll.state, AssignmentPoll.STATE_PUBLISHED) self.assertTrue(AssignmentVote.objects.exists()) - self.assertEquals(poll.amount_global_yes, Decimal("1")) - self.assertEquals(poll.amount_global_no, Decimal("2")) - self.assertEquals(poll.amount_global_abstain, Decimal("3")) + self.assertEqual(poll.amount_global_yes, Decimal("1")) + self.assertEqual(poll.amount_global_no, Decimal("2")) + self.assertEqual(poll.amount_global_abstain, Decimal("3")) option = poll.options.get(pk=1) self.assertEqual(option.yes, Decimal("0")) self.assertEqual(option.no, Decimal("1")) diff --git a/server/tests/integration/motions/test_polls.py b/server/tests/integration/motions/test_polls.py index e4bc1ed10..487053d96 100644 --- a/server/tests/integration/motions/test_polls.py +++ b/server/tests/integration/motions/test_polls.py @@ -897,14 +897,13 @@ class VoteMotionPollNamed(TestCase): self.start_poll() self.make_admin_delegate() self.make_admin_present() - user, _ = self.create_user() - user.groups.add(GROUP_DELEGATE_PK) + self.user, self.user_password = self.create_user() + self.user.groups.add(GROUP_DELEGATE_PK) if with_delegation: - user.vote_delegated_to = self.admin - user.save() + self.user.vote_delegated_to = self.admin + self.user.save() inform_changed_data(self.admin) # put the admin into the cache to update # its vote_delegated_to_id field - self.user = user def test_vote_delegation(self): self.setup_vote_delegation() @@ -958,7 +957,7 @@ class VoteMotionPollNamed(TestCase): reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "N", "user_id": self.user.pk}, ) - self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN) + self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST) self.assertFalse(MotionPoll.objects.get().get_votes().exists()) def test_vote_delegation_not_present(self): @@ -972,7 +971,7 @@ class VoteMotionPollNamed(TestCase): self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN) self.assertFalse(MotionPoll.objects.get().get_votes().exists()) - def test_vote_delegation_delegatee_not_in_group(self): + def test_vote_delegation_delegate_not_in_group(self): self.setup_vote_delegation() self.admin.groups.remove(GROUP_DELEGATE_PK) self.admin.save() @@ -999,6 +998,23 @@ class VoteMotionPollNamed(TestCase): self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN) self.assertFalse(MotionPoll.objects.get().get_votes().exists()) + def test_vote_delegation_delegator_self_vote_not_allowed(self): + self.setup_vote_delegation() + # Make the user a delegate and present + self.admin.groups.add(GROUP_DELEGATE_PK) + self.admin.groups.remove(GROUP_ADMIN_PK) + self.user.is_present = True + self.user.save() + # Use the user to make the request to vote for himself + user_client = APIClient() + user_client.login(username=self.user.username, password=self.user_password) + response = user_client.post( + reverse("motionpoll-vote", args=[self.poll.pk]), + {"data": "N"}, + ) + self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST) + self.assertFalse(MotionPoll.objects.get().get_votes().exists()) + class VoteMotionPollNamedAutoupdates(TestCase): """3 important users: