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.

This commit is contained in:
Finn Stutzenstein 2020-12-03 13:23:31 +01:00
parent ea4ec53fb1
commit 78f0b29921
No known key found for this signature in database
GPG Key ID: 9042F605C6324654
3 changed files with 42 additions and 12 deletions

View File

@ -255,15 +255,29 @@ class BasePollViewSet(ModelViewSet):
Analog: has to have manage permissions Analog: has to have manage permissions
Named & Pseudoanonymous: has to be in a poll group and present 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: 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 poll.type == BasePoll.TYPE_ANALOG:
if not self.has_manage_permissions(): if not self.has_manage_permissions():
self.permission_denied(request) self.permission_denied(request)
else: else:
if poll.state != BasePoll.STATE_STARTED: 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( if not request.user.is_present or not in_some_groups(
vote_user.id, vote_user.id,

View File

@ -470,9 +470,9 @@ class CreateAssignmentPoll(TestCase):
poll = AssignmentPoll.objects.get() poll = AssignmentPoll.objects.get()
self.assertEqual(poll.state, AssignmentPoll.STATE_PUBLISHED) self.assertEqual(poll.state, AssignmentPoll.STATE_PUBLISHED)
self.assertTrue(AssignmentVote.objects.exists()) self.assertTrue(AssignmentVote.objects.exists())
self.assertEquals(poll.amount_global_yes, Decimal("1")) self.assertEqual(poll.amount_global_yes, Decimal("1"))
self.assertEquals(poll.amount_global_no, Decimal("2")) self.assertEqual(poll.amount_global_no, Decimal("2"))
self.assertEquals(poll.amount_global_abstain, Decimal("3")) self.assertEqual(poll.amount_global_abstain, Decimal("3"))
option = poll.options.get(pk=1) option = poll.options.get(pk=1)
self.assertEqual(option.yes, Decimal("0")) self.assertEqual(option.yes, Decimal("0"))
self.assertEqual(option.no, Decimal("1")) self.assertEqual(option.no, Decimal("1"))

View File

@ -897,14 +897,13 @@ class VoteMotionPollNamed(TestCase):
self.start_poll() self.start_poll()
self.make_admin_delegate() self.make_admin_delegate()
self.make_admin_present() self.make_admin_present()
user, _ = self.create_user() self.user, self.user_password = self.create_user()
user.groups.add(GROUP_DELEGATE_PK) self.user.groups.add(GROUP_DELEGATE_PK)
if with_delegation: if with_delegation:
user.vote_delegated_to = self.admin self.user.vote_delegated_to = self.admin
user.save() self.user.save()
inform_changed_data(self.admin) # put the admin into the cache to update inform_changed_data(self.admin) # put the admin into the cache to update
# its vote_delegated_to_id field # its vote_delegated_to_id field
self.user = user
def test_vote_delegation(self): def test_vote_delegation(self):
self.setup_vote_delegation() self.setup_vote_delegation()
@ -958,7 +957,7 @@ class VoteMotionPollNamed(TestCase):
reverse("motionpoll-vote", args=[self.poll.pk]), reverse("motionpoll-vote", args=[self.poll.pk]),
{"data": "N", "user_id": self.user.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()) self.assertFalse(MotionPoll.objects.get().get_votes().exists())
def test_vote_delegation_not_present(self): def test_vote_delegation_not_present(self):
@ -972,7 +971,7 @@ class VoteMotionPollNamed(TestCase):
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN) self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
self.assertFalse(MotionPoll.objects.get().get_votes().exists()) 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.setup_vote_delegation()
self.admin.groups.remove(GROUP_DELEGATE_PK) self.admin.groups.remove(GROUP_DELEGATE_PK)
self.admin.save() self.admin.save()
@ -999,6 +998,23 @@ class VoteMotionPollNamed(TestCase):
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN) self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
self.assertFalse(MotionPoll.objects.get().get_votes().exists()) 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): class VoteMotionPollNamedAutoupdates(TestCase):
"""3 important users: """3 important users: