2019-10-18 14:18:49 +02:00
|
|
|
from decimal import Decimal
|
|
|
|
|
2019-10-29 12:58:37 +01:00
|
|
|
import pytest
|
2019-11-05 09:30:55 +01:00
|
|
|
from django.conf import settings
|
2019-10-18 14:18:49 +02:00
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from django.urls import reverse
|
|
|
|
from rest_framework import status
|
|
|
|
from rest_framework.test import APIClient
|
|
|
|
|
|
|
|
from openslides.core.config import config
|
2019-10-29 12:58:37 +01:00
|
|
|
from openslides.motions.models import Motion, MotionOption, MotionPoll, MotionVote
|
2019-10-18 14:18:49 +02:00
|
|
|
from openslides.poll.models import BasePoll
|
|
|
|
from openslides.utils.auth import get_group_model
|
|
|
|
from openslides.utils.autoupdate import inform_changed_data
|
|
|
|
from tests.common_groups import GROUP_ADMIN_PK, GROUP_DEFAULT_PK, GROUP_DELEGATE_PK
|
2019-11-01 09:11:12 +01:00
|
|
|
from tests.count_queries import count_queries
|
2019-10-18 14:18:49 +02:00
|
|
|
from tests.test_case import TestCase
|
|
|
|
|
2019-10-29 12:58:37 +01:00
|
|
|
|
|
|
|
@pytest.mark.django_db(transaction=False)
|
|
|
|
def test_motion_poll_db_queries():
|
|
|
|
"""
|
|
|
|
Tests that only the following db queries are done:
|
|
|
|
* 1 request to get the polls,
|
|
|
|
* 1 request to get all options for all polls,
|
|
|
|
* 1 request to get all votes for all options,
|
|
|
|
* 1 request to get all users for all votes,
|
|
|
|
* 1 request to get all poll groups,
|
|
|
|
= 5 queries
|
|
|
|
"""
|
|
|
|
create_motion_polls()
|
2019-11-04 14:56:01 +01:00
|
|
|
assert count_queries(MotionPoll.get_elements)() == 5
|
2019-10-29 12:58:37 +01:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.django_db(transaction=False)
|
|
|
|
def test_motion_vote_db_queries():
|
|
|
|
"""
|
|
|
|
Tests that only 1 query is done when fetching MotionVotes
|
|
|
|
"""
|
|
|
|
create_motion_polls()
|
2019-11-04 14:56:01 +01:00
|
|
|
assert count_queries(MotionVote.get_elements)() == 1
|
2019-10-29 12:58:37 +01:00
|
|
|
|
|
|
|
|
2020-02-12 17:18:01 +01:00
|
|
|
@pytest.mark.django_db(transaction=False)
|
|
|
|
def test_motion_option_db_queries():
|
|
|
|
"""
|
2020-02-13 18:24:51 +01:00
|
|
|
Tests that only the following db queries are done:
|
|
|
|
* 1 request to get the options,
|
|
|
|
* 1 request to get all votes for all options,
|
2020-03-11 10:22:03 +01:00
|
|
|
= 2 queries
|
2020-02-12 17:18:01 +01:00
|
|
|
"""
|
|
|
|
create_motion_polls()
|
2020-03-11 10:22:03 +01:00
|
|
|
assert count_queries(MotionOption.get_elements)() == 2
|
2020-02-12 17:18:01 +01:00
|
|
|
|
|
|
|
|
2019-10-29 12:58:37 +01:00
|
|
|
def create_motion_polls():
|
|
|
|
"""
|
|
|
|
Creates 1 Motion with 5 polls with 5 options each which have 2 votes each
|
|
|
|
"""
|
|
|
|
motion = Motion.objects.create(title="test_motion_wfLrsjEHXBmPplbvQ65N")
|
|
|
|
group1 = get_group_model().objects.get(pk=1)
|
|
|
|
group2 = get_group_model().objects.get(pk=2)
|
|
|
|
|
|
|
|
for index in range(5):
|
|
|
|
poll = MotionPoll.objects.create(
|
|
|
|
motion=motion, title=f"test_title_{index}", pollmethod="YN", type="named"
|
|
|
|
)
|
|
|
|
poll.groups.add(group1)
|
|
|
|
poll.groups.add(group2)
|
|
|
|
|
|
|
|
for j in range(5):
|
|
|
|
option = MotionOption.objects.create(poll=poll)
|
|
|
|
|
|
|
|
for k in range(2):
|
|
|
|
user = get_user_model().objects.create_user(
|
|
|
|
username=f"test_username_{index}{j}{k}",
|
|
|
|
password="test_password_kbzj5L8ZtVxBllZzoW6D",
|
|
|
|
)
|
|
|
|
MotionVote.objects.create(
|
|
|
|
user=user,
|
|
|
|
option=option,
|
|
|
|
value=("Y" if k == 0 else "N"),
|
|
|
|
weight=Decimal(1),
|
|
|
|
)
|
2020-03-11 10:22:03 +01:00
|
|
|
poll.voted.add(user)
|
2019-10-29 12:58:37 +01:00
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class CreateMotionPoll(TestCase):
|
|
|
|
"""
|
|
|
|
Tests creating polls of motions.
|
|
|
|
"""
|
|
|
|
|
2019-11-12 18:30:26 +01:00
|
|
|
def advancedSetUp(self):
|
2019-10-18 14:18:49 +02:00
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_Aiqueigh2dae9phabiqu",
|
|
|
|
text="test_text_Neekoh3zou6li5rue8iL",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
|
|
|
|
def test_simple(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_ailai4toogh3eefaa2Vo",
|
|
|
|
"pollmethod": "YNA",
|
|
|
|
"type": "named",
|
|
|
|
"motion_id": self.motion.id,
|
2019-10-29 09:44:19 +01:00
|
|
|
"onehundred_percent_base": "YN",
|
|
|
|
"majority_method": "simple",
|
2019-10-18 14:18:49 +02:00
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertTrue(MotionPoll.objects.exists())
|
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
self.assertEqual(poll.is_pseudoanonymized, False)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.title, "test_title_ailai4toogh3eefaa2Vo")
|
|
|
|
self.assertEqual(poll.pollmethod, "YNA")
|
|
|
|
self.assertEqual(poll.type, "named")
|
|
|
|
self.assertEqual(poll.motion.id, self.motion.id)
|
|
|
|
self.assertTrue(poll.options.exists())
|
|
|
|
|
2020-01-21 09:33:33 +01:00
|
|
|
def test_default_method(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_ailai4toogh3eefaa2Vo",
|
|
|
|
"type": "named",
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": "YN",
|
|
|
|
"majority_method": "simple",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
|
|
|
self.assertTrue(MotionPoll.objects.exists())
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.pollmethod, "YNA")
|
|
|
|
|
2019-10-29 09:44:19 +01:00
|
|
|
def test_missing_keys(self):
|
|
|
|
complete_request_data = {
|
|
|
|
"title": "test_title_OoCh9aitaeyaeth8nom1",
|
|
|
|
"type": "named",
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": "YN",
|
|
|
|
"majority_method": "simple",
|
|
|
|
}
|
|
|
|
for key in complete_request_data.keys():
|
|
|
|
request_data = {
|
|
|
|
_key: value
|
|
|
|
for _key, value in complete_request_data.items()
|
|
|
|
if _key != key
|
|
|
|
}
|
|
|
|
response = self.client.post(reverse("motionpoll-list"), request_data)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-29 09:44:19 +01:00
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_with_groups(self):
|
|
|
|
group1 = get_group_model().objects.get(pk=1)
|
|
|
|
group2 = get_group_model().objects.get(pk=2)
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_Thoo2eiphohhi1eeXoow",
|
|
|
|
"pollmethod": "YNA",
|
|
|
|
"type": "named",
|
|
|
|
"motion_id": self.motion.id,
|
2019-10-29 09:44:19 +01:00
|
|
|
"onehundred_percent_base": "YN",
|
|
|
|
"majority_method": "simple",
|
2019-10-18 14:18:49 +02:00
|
|
|
"groups_id": [1, 2],
|
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertTrue(group1 in poll.groups.all())
|
|
|
|
self.assertTrue(group2 in poll.groups.all())
|
|
|
|
|
|
|
|
def test_with_empty_groups(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_Thoo2eiphohhi1eeXoow",
|
2019-11-05 09:30:55 +01:00
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YNA,
|
|
|
|
"type": MotionPoll.TYPE_NAMED,
|
2019-10-18 14:18:49 +02:00
|
|
|
"motion_id": self.motion.id,
|
2019-11-05 09:30:55 +01:00
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YN,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
2019-10-18 14:18:49 +02:00
|
|
|
"groups_id": [],
|
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertFalse(poll.groups.exists())
|
|
|
|
|
|
|
|
def test_not_supported_type(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_yaiyeighoh0Iraet3Ahc",
|
2019-11-05 09:30:55 +01:00
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YNA,
|
2019-10-18 14:18:49 +02:00
|
|
|
"type": "not_existing",
|
|
|
|
"motion_id": self.motion.id,
|
2019-11-05 09:30:55 +01:00
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YN,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-11-05 09:30:55 +01:00
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
|
|
|
|
|
|
|
def test_not_allowed_type(self):
|
|
|
|
setattr(settings, "ENABLE_ELECTRONIC_VOTING", False)
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_3jdWIXbKBa7ZXutf3RYf",
|
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YN,
|
|
|
|
"type": MotionPoll.TYPE_NAMED,
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YN,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
2019-10-18 14:18:49 +02:00
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
2019-11-05 09:30:55 +01:00
|
|
|
setattr(settings, "ENABLE_ELECTRONIC_VOTING", True)
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_not_supported_pollmethod(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_SeVaiteYeiNgie5Xoov8",
|
|
|
|
"pollmethod": "not_existing",
|
|
|
|
"type": "named",
|
|
|
|
"motion_id": self.motion.id,
|
2019-11-05 09:30:55 +01:00
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YN,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
2019-10-18 14:18:49 +02:00
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
|
|
|
|
|
|
|
def test_create_with_votes(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_0X5LifVkKiSh8OPGQM8e",
|
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YN,
|
|
|
|
"type": MotionPoll.TYPE_ANALOG,
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YNA,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
|
|
|
"votes": {
|
|
|
|
"Y": 1,
|
|
|
|
"N": 2,
|
|
|
|
"votesvalid": "-2",
|
|
|
|
"votesinvalid": "-2",
|
|
|
|
"votescast": "-2",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_FINISHED)
|
|
|
|
self.assertTrue(MotionVote.objects.exists())
|
|
|
|
|
|
|
|
def test_create_with_votes_publish_immediately(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_iXhJX0jmNl3Nvadsi8JO",
|
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YN,
|
|
|
|
"type": MotionPoll.TYPE_ANALOG,
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YNA,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
|
|
|
"votes": {
|
|
|
|
"Y": 1,
|
|
|
|
"N": 2,
|
|
|
|
"votesvalid": "-2",
|
|
|
|
"votesinvalid": "-2",
|
|
|
|
"votescast": "-2",
|
|
|
|
},
|
|
|
|
"publish_immediately": "1",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_201_CREATED)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_PUBLISHED)
|
|
|
|
self.assertTrue(MotionVote.objects.exists())
|
|
|
|
|
|
|
|
def test_create_with_invalid_votes(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_phSl1IALPIoDyM9uI2Kq",
|
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YN,
|
|
|
|
"type": MotionPoll.TYPE_ANALOG,
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YNA,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
|
|
|
"votes": {"Y": 1, "N": 2, "votesvalid": "-2", "votesinvalid": "-2"},
|
|
|
|
"publish_immediately": "1",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertFalse(MotionVote.objects.exists())
|
|
|
|
|
|
|
|
def test_create_with_votes_wrong_type(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-list"),
|
|
|
|
{
|
|
|
|
"title": "test_title_PgvqRIvuKuVImEpQJAMZ",
|
|
|
|
"pollmethod": MotionPoll.POLLMETHOD_YN,
|
|
|
|
"type": MotionPoll.TYPE_NAMED,
|
|
|
|
"motion_id": self.motion.id,
|
|
|
|
"onehundred_percent_base": MotionPoll.PERCENT_BASE_YNA,
|
|
|
|
"majority_method": MotionPoll.MAJORITY_SIMPLE,
|
|
|
|
"votes": {"Y": 1, "N": 2, "votesvalid": "-2", "votesinvalid": "-2"},
|
|
|
|
"publish_immediately": "1",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
|
|
|
self.assertFalse(MotionPoll.objects.exists())
|
|
|
|
self.assertFalse(MotionVote.objects.exists())
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
class UpdateMotionPoll(TestCase):
|
|
|
|
"""
|
|
|
|
Tests updating polls of motions.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_Aiqueigh2dae9phabiqu",
|
|
|
|
text="test_text_Neekoh3zou6li5rue8iL",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.group = get_group_model().objects.get(pk=1)
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_beeFaihuNae1vej2ai8m",
|
2019-10-29 09:44:19 +01:00
|
|
|
pollmethod="YNA",
|
2019-10-18 14:18:49 +02:00
|
|
|
type="named",
|
2019-10-29 09:44:19 +01:00
|
|
|
onehundred_percent_base="YN",
|
|
|
|
majority_method="simple",
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.poll.groups.add(self.group)
|
|
|
|
|
|
|
|
def test_patch_title(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"title": "test_title_Aishohh1ohd0aiSut7gi"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.title, "test_title_Aishohh1ohd0aiSut7gi")
|
|
|
|
|
|
|
|
def test_prevent_patching_motion(self):
|
|
|
|
motion = Motion(
|
|
|
|
title="test_title_phohdah8quukooHeetuz",
|
|
|
|
text="test_text_ue2yeisaech1ahBohhoo",
|
|
|
|
)
|
|
|
|
motion.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"motion_id": motion.id}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.motion.id, self.motion.id) # unchanged
|
|
|
|
|
|
|
|
def test_patch_pollmethod(self):
|
|
|
|
response = self.client.patch(
|
2019-10-29 09:44:19 +01:00
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"pollmethod": "YN"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2019-10-29 09:44:19 +01:00
|
|
|
self.assertEqual(poll.pollmethod, "YN")
|
|
|
|
self.assertEqual(poll.onehundred_percent_base, "YN")
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_patch_invalid_pollmethod(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"pollmethod": "invalid"}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2019-10-29 09:44:19 +01:00
|
|
|
self.assertEqual(poll.pollmethod, "YNA")
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_patch_type(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"type": "analog"}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.type, "analog")
|
|
|
|
|
2021-03-25 13:13:49 +01:00
|
|
|
def test_patch_type_to_pseudoanonymous(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"type": BasePoll.TYPE_PSEUDOANONYMOUS},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.type, BasePoll.TYPE_PSEUDOANONYMOUS)
|
|
|
|
self.assertTrue(poll.is_pseudoanonymized)
|
|
|
|
|
|
|
|
def test_patch_type_to_named(self):
|
|
|
|
self.test_patch_type_to_pseudoanonymous()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"type": BasePoll.TYPE_NAMED},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.type, BasePoll.TYPE_NAMED)
|
|
|
|
self.assertFalse(poll.is_pseudoanonymized)
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
def test_patch_invalid_type(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"type": "invalid"}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.type, "named")
|
|
|
|
|
2019-11-05 09:30:55 +01:00
|
|
|
def test_patch_not_allowed_type(self):
|
|
|
|
setattr(settings, "ENABLE_ELECTRONIC_VOTING", False)
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"type": BasePoll.TYPE_NAMED},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-11-05 09:30:55 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.type, BasePoll.TYPE_NAMED)
|
|
|
|
setattr(settings, "ENABLE_ELECTRONIC_VOTING", True)
|
|
|
|
|
2019-10-29 09:44:19 +01:00
|
|
|
def test_patch_100_percent_base(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"onehundred_percent_base": "cast"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-29 09:44:19 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.onehundred_percent_base, "cast")
|
|
|
|
|
|
|
|
def test_patch_wrong_100_percent_base(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"onehundred_percent_base": "invalid"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-29 09:44:19 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.onehundred_percent_base, "YN")
|
|
|
|
|
|
|
|
def test_patch_majority_method(self):
|
2019-10-18 14:18:49 +02:00
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
2019-10-29 09:44:19 +01:00
|
|
|
{"majority_method": "two_thirds"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-29 09:44:19 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.majority_method, "two_thirds")
|
|
|
|
|
|
|
|
def test_patch_wrong_majority_method(self):
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"majority_method": "invalid majority method"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-29 09:44:19 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.majority_method, "simple")
|
|
|
|
|
|
|
|
def test_patch_groups_to_empty(self):
|
|
|
|
response = self.client.patch(
|
2020-08-31 13:24:16 +02:00
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]), {"groups_id": []}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertFalse(poll.groups.exists())
|
|
|
|
|
|
|
|
def test_patch_groups(self):
|
|
|
|
group2 = get_group_model().objects.get(pk=2)
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"groups_id": [group2.id]},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.groups.count(), 1)
|
|
|
|
self.assertEqual(poll.groups.get(), group2)
|
|
|
|
|
2019-11-12 18:30:26 +01:00
|
|
|
def test_patch_title_started(self):
|
|
|
|
self.poll.state = 2
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"title": "test_title_1FjLGeQqsi9GgNzPp73S"},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.title, "test_title_1FjLGeQqsi9GgNzPp73S")
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
def test_patch_wrong_state(self):
|
|
|
|
self.poll.state = 2
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
2019-11-12 18:30:26 +01:00
|
|
|
{"type": BasePoll.TYPE_NAMED},
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertEqual(poll.type, BasePoll.TYPE_NAMED)
|
2019-10-18 14:18:49 +02:00
|
|
|
|
2019-11-27 15:44:17 +01:00
|
|
|
def test_patch_majority_method_state_not_created(self):
|
|
|
|
self.poll.state = 2
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"majority_method": "two_thirds"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-11-27 15:44:17 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.majority_method, "two_thirds")
|
|
|
|
|
|
|
|
def test_patch_100_percent_base_state_not_created(self):
|
|
|
|
self.poll.state = 2
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"onehundred_percent_base": "cast"},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-11-27 15:44:17 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.onehundred_percent_base, "cast")
|
|
|
|
|
|
|
|
def test_patch_wrong_100_percent_base_state_not_created(self):
|
|
|
|
self.poll.state = 2
|
|
|
|
self.poll.pollmethod = MotionPoll.POLLMETHOD_YN
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.patch(
|
|
|
|
reverse("motionpoll-detail", args=[self.poll.pk]),
|
|
|
|
{"onehundred_percent_base": MotionPoll.PERCENT_BASE_YNA},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-11-27 15:44:17 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.onehundred_percent_base, "YN")
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class VoteMotionPollAnalog(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_OoK9IeChe2Jeib9Deeji",
|
|
|
|
text="test_text_eichui1oobiSeit9aifo",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_tho8PhiePh8upaex6phi",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_ANALOG,
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
|
|
|
|
def start_poll(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
|
|
|
|
def make_admin_delegate(self):
|
|
|
|
admin = get_user_model().objects.get(username="admin")
|
|
|
|
admin.groups.add(GROUP_DELEGATE_PK)
|
|
|
|
admin.groups.remove(GROUP_ADMIN_PK)
|
|
|
|
inform_changed_data(admin)
|
|
|
|
|
|
|
|
def test_start_poll(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-start", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_STARTED)
|
|
|
|
self.assertEqual(poll.votesvalid, None)
|
|
|
|
self.assertEqual(poll.votesinvalid, None)
|
|
|
|
self.assertEqual(poll.votescast, None)
|
|
|
|
self.assertFalse(poll.get_votes().exists())
|
|
|
|
|
2019-11-13 07:46:13 +01:00
|
|
|
def test_stop_poll(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-11-13 07:46:13 +01:00
|
|
|
self.assertEqual(self.poll.state, MotionPoll.STATE_STARTED)
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
def test_vote(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{
|
2020-09-10 12:09:05 +02:00
|
|
|
"data": {
|
|
|
|
"Y": "1",
|
|
|
|
"N": "2.35",
|
|
|
|
"A": "-1",
|
|
|
|
"votesvalid": "4.64",
|
|
|
|
"votesinvalid": "-2",
|
|
|
|
"votescast": "-2",
|
|
|
|
},
|
2019-10-18 14:18:49 +02:00
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("4.64"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("-2"))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertEqual(poll.votescast, Decimal("-2"))
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.get_votes().count(), 3)
|
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_FINISHED)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("1"))
|
|
|
|
self.assertEqual(option.no, Decimal("2.35"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("-1"))
|
|
|
|
|
|
|
|
def test_vote_no_permissions(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2020-09-10 12:09:05 +02:00
|
|
|
def test_vote_no_data(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(reverse("motionpoll-vote", args=[self.poll.pk]), {})
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
def test_vote_missing_data(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": {"Y": "4", "N": "22.6"}},
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_data_format(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": [1, 2, 5]}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_vote_data(self):
|
|
|
|
self.start_poll()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
2020-09-10 12:09:05 +02:00
|
|
|
{"data": {"Y": "some string", "N": "-2", "A": "3"}},
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2019-11-27 15:44:17 +01:00
|
|
|
def test_vote_state_finished(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{
|
2020-09-10 12:09:05 +02:00
|
|
|
"data": {
|
|
|
|
"Y": "3",
|
|
|
|
"N": "1",
|
|
|
|
"A": "5",
|
|
|
|
"votesvalid": "-2",
|
|
|
|
"votesinvalid": "1",
|
|
|
|
"votescast": "-1",
|
|
|
|
},
|
2019-11-27 15:44:17 +01:00
|
|
|
},
|
|
|
|
)
|
|
|
|
self.poll.state = 3
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{
|
2020-09-10 12:09:05 +02:00
|
|
|
"data": {
|
|
|
|
"Y": "1",
|
|
|
|
"N": "2.35",
|
|
|
|
"A": "-1",
|
|
|
|
"votesvalid": "4.64",
|
|
|
|
"votesinvalid": "-2",
|
|
|
|
"votescast": "3",
|
|
|
|
},
|
2019-11-27 15:44:17 +01:00
|
|
|
},
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-11-27 15:44:17 +01:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-11-27 15:44:17 +01:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("4.64"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("-2"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("3"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 3)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("1"))
|
|
|
|
self.assertEqual(option.no, Decimal("2.35"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("-1"))
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class VoteMotionPollNamed(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_OoK9IeChe2Jeib9Deeji",
|
|
|
|
text="test_text_eichui1oobiSeit9aifo",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.group = get_group_model().objects.get(pk=GROUP_DELEGATE_PK)
|
|
|
|
self.admin = get_user_model().objects.get(username="admin")
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_tho8PhiePh8upaex6phi",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_NAMED,
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.poll.groups.add(self.group)
|
|
|
|
|
|
|
|
def start_poll(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
|
|
|
|
def make_admin_delegate(self):
|
|
|
|
self.admin.groups.add(GROUP_DELEGATE_PK)
|
|
|
|
self.admin.groups.remove(GROUP_ADMIN_PK)
|
|
|
|
inform_changed_data(self.admin)
|
|
|
|
|
|
|
|
def make_admin_present(self):
|
|
|
|
self.admin.is_present = True
|
|
|
|
self.admin.save()
|
|
|
|
|
|
|
|
def test_start_poll(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-start", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_STARTED)
|
|
|
|
self.assertEqual(poll.votesvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("0"))
|
|
|
|
self.assertFalse(poll.get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "N"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("1"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("1"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.user, self.admin)
|
2020-04-22 16:54:50 +02:00
|
|
|
self.assertEqual(vote.weight, Decimal("1"))
|
|
|
|
|
|
|
|
def test_vote_with_voteweight(self):
|
|
|
|
config["users_activate_vote_weight"] = True
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
self.admin.vote_weight = weight = Decimal("3.5")
|
|
|
|
self.admin.save()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "A"}
|
2020-04-22 16:54:50 +02:00
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2020-04-22 16:54:50 +02:00
|
|
|
self.assertEqual(poll.votesvalid, weight)
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
2020-04-30 08:10:39 +02:00
|
|
|
self.assertEqual(poll.votescast, Decimal("1"))
|
2020-04-22 16:54:50 +02:00
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("0"))
|
|
|
|
self.assertEqual(option.abstain, weight)
|
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.weight, weight)
|
|
|
|
|
|
|
|
def test_vote_without_voteweight(self):
|
|
|
|
self.admin.vote_weight = Decimal("3.5")
|
|
|
|
self.admin.save()
|
|
|
|
self.test_vote()
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_change_vote(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "N"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "A"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2020-04-06 14:14:00 +02:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("1"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("1"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
2020-04-06 14:14:00 +02:00
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
2019-10-18 14:18:49 +02:00
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.user, self.admin)
|
|
|
|
|
|
|
|
def test_vote_anonymous(self):
|
|
|
|
self.poll.groups.add(GROUP_DEFAULT_PK)
|
|
|
|
self.start_poll()
|
|
|
|
config["general_system_enable_anonymous"] = True
|
|
|
|
guest_client = APIClient()
|
|
|
|
response = guest_client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "Y"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_state(self):
|
|
|
|
self.make_admin_present()
|
|
|
|
self.make_admin_delegate()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_group(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_present()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_not_present(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_missing_data(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_data_format(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": [1, 2, 5]}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2020-09-10 12:09:05 +02:00
|
|
|
def setup_vote_delegation(self, with_delegation=True):
|
2021-04-26 08:31:22 +02:00
|
|
|
"""user -> admin"""
|
2020-09-10 12:09:05 +02:00
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
2020-12-03 13:23:31 +01:00
|
|
|
self.user, self.user_password = self.create_user()
|
|
|
|
self.user.groups.add(GROUP_DELEGATE_PK)
|
2020-09-10 12:09:05 +02:00
|
|
|
if with_delegation:
|
2020-12-03 13:23:31 +01:00
|
|
|
self.user.vote_delegated_to = self.admin
|
|
|
|
self.user.save()
|
2020-09-10 12:09:05 +02:00
|
|
|
inform_changed_data(self.admin) # put the admin into the cache to update
|
|
|
|
# its vote_delegated_to_id field
|
|
|
|
|
|
|
|
def test_vote_delegation(self):
|
|
|
|
self.setup_vote_delegation()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": "N", "user_id": self.user.pk}, # user not present
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2020-09-10 12:09:05 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("1"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("1"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.user, self.user)
|
|
|
|
self.assertEqual(vote.delegated_user, self.admin)
|
|
|
|
|
|
|
|
def test_vote_delegation_and_self_vote(self):
|
|
|
|
self.test_vote_delegation()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "Y"}
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2020-09-10 12:09:05 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("2"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("2"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 2)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("1"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
|
|
|
vote = option.votes.get(user_id=self.admin.pk)
|
|
|
|
self.assertEqual(vote.user, self.admin)
|
|
|
|
self.assertEqual(vote.delegated_user, self.admin)
|
|
|
|
|
|
|
|
def test_vote_delegation_forbidden(self):
|
|
|
|
self.setup_vote_delegation(False)
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": "N", "user_id": self.user.pk},
|
|
|
|
)
|
2020-12-03 13:23:31 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2020-09-10 12:09:05 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_delegation_not_present(self):
|
|
|
|
self.setup_vote_delegation()
|
|
|
|
self.admin.is_present = False
|
|
|
|
self.admin.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": "N", "user_id": self.user.pk},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2020-12-03 13:23:31 +01:00
|
|
|
def test_vote_delegation_delegate_not_in_group(self):
|
2020-09-10 12:09:05 +02:00
|
|
|
self.setup_vote_delegation()
|
|
|
|
self.admin.groups.remove(GROUP_DELEGATE_PK)
|
|
|
|
self.admin.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": "N", "user_id": self.user.pk},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
vote = poll.get_votes()[0]
|
|
|
|
self.assertEqual(vote.value, "N")
|
|
|
|
self.assertEqual(vote.user, self.user)
|
|
|
|
self.assertEqual(vote.delegated_user, self.admin)
|
|
|
|
|
|
|
|
def test_vote_delegation_delegator_not_in_group(self):
|
|
|
|
self.setup_vote_delegation()
|
|
|
|
self.user.groups.remove(GROUP_DELEGATE_PK)
|
|
|
|
self.user.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]),
|
|
|
|
{"data": "N", "user_id": self.user.pk},
|
|
|
|
)
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
2020-12-03 13:23:31 +01:00
|
|
|
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())
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class VoteMotionPollPseudoanonymous(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_Chaebaenges1aebe8iev",
|
|
|
|
text="test_text_cah2aigh6ahc8OhNguQu",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.group = get_group_model().objects.get(pk=GROUP_DELEGATE_PK)
|
|
|
|
self.admin = get_user_model().objects.get(username="admin")
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_yohphei9Iegohqu9ki7m",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_PSEUDOANONYMOUS,
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.poll.groups.add(self.group)
|
|
|
|
|
|
|
|
def start_poll(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
|
|
|
|
def make_admin_delegate(self):
|
|
|
|
self.admin.groups.add(GROUP_DELEGATE_PK)
|
|
|
|
self.admin.groups.remove(GROUP_ADMIN_PK)
|
|
|
|
inform_changed_data(self.admin)
|
|
|
|
|
|
|
|
def make_admin_present(self):
|
|
|
|
self.admin.is_present = True
|
|
|
|
self.admin.save()
|
|
|
|
|
|
|
|
def test_start_poll(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-start", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_STARTED)
|
|
|
|
self.assertEqual(poll.votesvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("0"))
|
|
|
|
self.assertFalse(poll.get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "N"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.votesvalid, Decimal("1"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("1"))
|
|
|
|
self.assertEqual(poll.get_votes().count(), 1)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
2020-03-11 10:22:03 +01:00
|
|
|
self.assertTrue(self.admin in poll.voted.all())
|
2019-10-18 14:18:49 +02:00
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.user, None)
|
|
|
|
|
|
|
|
def test_change_vote(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "N"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "A"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2020-02-13 18:24:51 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
option = MotionPoll.objects.get().options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
|
|
|
vote = option.votes.get()
|
|
|
|
self.assertEqual(vote.user, None)
|
|
|
|
|
|
|
|
def test_vote_anonymous(self):
|
|
|
|
self.poll.groups.add(GROUP_DEFAULT_PK)
|
|
|
|
self.start_poll()
|
|
|
|
config["general_system_enable_anonymous"] = True
|
|
|
|
guest_client = APIClient()
|
|
|
|
response = guest_client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": "Y"}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_state(self):
|
|
|
|
self.make_admin_present()
|
|
|
|
self.make_admin_delegate()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_group(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_present()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_not_present(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_403_FORBIDDEN)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_missing_data(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
2020-09-10 12:09:05 +02:00
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": {}}
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
def test_vote_wrong_data_format(self):
|
|
|
|
self.start_poll()
|
|
|
|
self.make_admin_delegate()
|
|
|
|
self.make_admin_present()
|
|
|
|
response = self.client.post(
|
2020-09-10 12:09:05 +02:00
|
|
|
reverse("motionpoll-vote", args=[self.poll.pk]), {"data": [1, 2, 5]}
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertFalse(MotionPoll.objects.get().get_votes().exists())
|
|
|
|
|
|
|
|
|
|
|
|
class StopMotionPoll(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_eiri4iipeemaeGhahkae",
|
|
|
|
text="test_text_eegh7quoochaiNgiyeix",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_Hu9Miebopaighee3EDie",
|
|
|
|
pollmethod="YNA",
|
2019-11-13 07:46:13 +01:00
|
|
|
type=BasePoll.TYPE_NAMED,
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
|
|
|
|
def test_stop_poll(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(MotionPoll.objects.get().state, MotionPoll.STATE_FINISHED)
|
|
|
|
|
|
|
|
def test_stop_wrong_state(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(MotionPoll.objects.get().state, MotionPoll.STATE_CREATED)
|
|
|
|
|
2021-03-25 13:13:49 +01:00
|
|
|
def setup_entitled_users(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
self.admin = get_user_model().objects.get(username="admin")
|
|
|
|
self.admin.is_present = True
|
|
|
|
self.admin.save()
|
|
|
|
self.group = get_group_model().objects.get(pk=GROUP_ADMIN_PK)
|
|
|
|
self.poll.groups.add(self.group)
|
|
|
|
|
|
|
|
def test_stop_poll_with_entitled_users(self):
|
|
|
|
self.setup_entitled_users()
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
self.assertEqual(
|
|
|
|
MotionPoll.objects.get().entitled_users_at_stop,
|
|
|
|
[{"user_id": self.admin.id, "voted": False, "vote_delegated_to_id": None}],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_stop_poll_with_entitled_users_and_vote_delegation(self):
|
|
|
|
self.setup_entitled_users()
|
|
|
|
user, _ = self.create_user()
|
2021-04-26 15:44:42 +02:00
|
|
|
user.is_present = True
|
|
|
|
user.save()
|
|
|
|
self.admin.is_present = False
|
2021-03-25 13:13:49 +01:00
|
|
|
self.admin.vote_delegated_to = user
|
|
|
|
self.admin.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
self.assertEqual(
|
|
|
|
MotionPoll.objects.get().entitled_users_at_stop,
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"user_id": self.admin.id,
|
|
|
|
"voted": False,
|
|
|
|
"vote_delegated_to_id": user.id,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
2021-05-06 16:06:52 +02:00
|
|
|
def test_stop_poll_multiple_users_database_query_count(self):
|
|
|
|
"""
|
|
|
|
The code in BasePoll.stop() should not make too much queries.
|
|
|
|
"""
|
|
|
|
self.setup_entitled_users()
|
|
|
|
expected = []
|
|
|
|
for _ in range(10):
|
|
|
|
user, _ = self.create_user()
|
|
|
|
user.is_present = True
|
|
|
|
user.vote_delegated_to = self.admin
|
|
|
|
user.save()
|
|
|
|
user.groups.add(self.group)
|
|
|
|
expected.append(
|
|
|
|
{
|
|
|
|
"user_id": user.id,
|
|
|
|
"voted": False,
|
|
|
|
"vote_delegated_to_id": self.admin.id,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
self.admin.is_present = False
|
|
|
|
self.admin.save()
|
|
|
|
config["users_activate_vote_weight"] = True
|
|
|
|
self.assertEqual(count_queries(self.poll.stop)(), 13)
|
|
|
|
self.assertEqual(MotionPoll.objects.get().entitled_users_at_stop, expected)
|
|
|
|
|
2021-04-08 10:47:26 +02:00
|
|
|
def test_stop_poll_assert_no_duplicate_entitled_users(self):
|
|
|
|
self.setup_entitled_users()
|
|
|
|
delegate_group = get_group_model().objects.get(pk=GROUP_DELEGATE_PK)
|
|
|
|
self.admin.groups.add(delegate_group)
|
|
|
|
self.poll.groups.add(delegate_group)
|
|
|
|
|
|
|
|
response = self.client.post(reverse("motionpoll-stop", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
self.assertEqual(
|
|
|
|
MotionPoll.objects.get().entitled_users_at_stop,
|
|
|
|
[{"user_id": self.admin.id, "voted": False, "vote_delegated_to_id": None}],
|
|
|
|
)
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class PublishMotionPoll(TestCase):
|
|
|
|
def advancedSetUp(self):
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_lai8Ho5gai9aijahRasu",
|
|
|
|
text="test_text_KieGhosh8ahWiguHeu2D",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_Nufae0iew7Iorox2thoo",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_PSEUDOANONYMOUS,
|
2019-10-29 09:44:19 +01:00
|
|
|
onehundred_percent_base="YN",
|
|
|
|
majority_method="simple",
|
2019-10-18 14:18:49 +02:00
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
option = self.poll.options.get()
|
|
|
|
self.user, _ = self.create_user()
|
|
|
|
self.vote = MotionVote.objects.create(
|
|
|
|
option=option, user=None, weight=Decimal(2), value="N"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_publish_poll(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_FINISHED
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-publish", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(MotionPoll.objects.get().state, MotionPoll.STATE_PUBLISHED)
|
|
|
|
|
|
|
|
def test_publish_wrong_state(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-publish", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(MotionPoll.objects.get().state, MotionPoll.STATE_CREATED)
|
|
|
|
|
2021-05-26 17:53:46 +02:00
|
|
|
def test_publish_from_started(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-publish", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
self.assertEqual(MotionPoll.objects.get().state, MotionPoll.STATE_PUBLISHED)
|
|
|
|
|
|
|
|
def test_publish_from_started_with_entitled_users(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_STARTED
|
|
|
|
self.poll.save()
|
|
|
|
admin = get_user_model().objects.get(username="admin")
|
|
|
|
admin.is_present = True
|
|
|
|
admin.save()
|
|
|
|
self.poll.groups.add(GROUP_ADMIN_PK)
|
|
|
|
response = self.client.post(reverse("motionpoll-publish", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.state, MotionPoll.STATE_PUBLISHED)
|
|
|
|
self.assertEqual(
|
|
|
|
poll.entitled_users_at_stop,
|
|
|
|
[{"user_id": admin.id, "voted": False, "vote_delegated_to_id": None}],
|
|
|
|
)
|
|
|
|
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
class PseudoanonymizeMotionPoll(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.client = APIClient()
|
|
|
|
self.client.login(username="admin", password="admin")
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_lai8Ho5gai9aijahRasu",
|
|
|
|
text="test_text_KieGhosh8ahWiguHeu2D",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_Nufae0iew7Iorox2thoo",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_NAMED,
|
|
|
|
state=MotionPoll.STATE_FINISHED,
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.option = self.poll.options.get()
|
|
|
|
self.user1, _ = self.create_user()
|
|
|
|
self.vote1 = MotionVote.objects.create(
|
|
|
|
user=self.user1, option=self.option, value="Y", weight=Decimal(1)
|
|
|
|
)
|
2020-03-11 10:22:03 +01:00
|
|
|
self.poll.voted.add(self.user1)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.user2, _ = self.create_user()
|
|
|
|
self.vote2 = MotionVote.objects.create(
|
|
|
|
user=self.user2, option=self.option, value="N", weight=Decimal(1)
|
|
|
|
)
|
2020-03-11 10:22:03 +01:00
|
|
|
self.poll.voted.add(self.user2)
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_pseudoanonymize_poll(self):
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-pseudoanonymize", args=[self.poll.pk])
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
2021-03-25 13:13:49 +01:00
|
|
|
poll.calculate_votes()
|
|
|
|
self.assertEqual(poll.is_pseudoanonymized, True)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.assertEqual(poll.get_votes().count(), 2)
|
|
|
|
self.assertEqual(poll.votesvalid, Decimal("2"))
|
|
|
|
self.assertEqual(poll.votesinvalid, Decimal("0"))
|
|
|
|
self.assertEqual(poll.votescast, Decimal("2"))
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("1"))
|
|
|
|
self.assertEqual(option.no, Decimal("1"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
2020-03-11 10:22:03 +01:00
|
|
|
self.assertTrue(self.user1 in poll.voted.all())
|
|
|
|
self.assertTrue(self.user2 in poll.voted.all())
|
2019-10-18 14:18:49 +02:00
|
|
|
for vote in poll.get_votes().all():
|
|
|
|
self.assertTrue(vote.user is None)
|
|
|
|
|
|
|
|
def test_pseudoanonymize_wrong_state(self):
|
|
|
|
self.poll.state = MotionPoll.STATE_CREATED
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-pseudoanonymize", args=[self.poll.pk])
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertTrue(poll.get_votes().filter(user=self.user1).exists())
|
|
|
|
self.assertTrue(poll.get_votes().filter(user=self.user2).exists())
|
|
|
|
|
|
|
|
def test_pseudoanonymize_wrong_type(self):
|
|
|
|
self.poll.type = MotionPoll.TYPE_ANALOG
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(
|
|
|
|
reverse("motionpoll-pseudoanonymize", args=[self.poll.pk])
|
|
|
|
)
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_400_BAD_REQUEST)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertTrue(poll.get_votes().filter(user=self.user1).exists())
|
|
|
|
self.assertTrue(poll.get_votes().filter(user=self.user2).exists())
|
|
|
|
|
|
|
|
|
|
|
|
class ResetMotionPoll(TestCase):
|
|
|
|
def advancedSetUp(self):
|
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_cheiJ1ieph5ohng9queu",
|
|
|
|
text="test_text_yahng6fiegaL7mooZ2of",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_oozie2Ui9xie0chaghie",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_ANALOG,
|
|
|
|
state=MotionPoll.STATE_FINISHED,
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.option = self.poll.options.get()
|
|
|
|
self.user1, _ = self.create_user()
|
|
|
|
self.vote1 = MotionVote.objects.create(
|
|
|
|
user=self.user1, option=self.option, value="Y", weight=Decimal(1)
|
|
|
|
)
|
2020-03-11 10:22:03 +01:00
|
|
|
self.poll.voted.add(self.user1)
|
2019-10-18 14:18:49 +02:00
|
|
|
self.user2, _ = self.create_user()
|
|
|
|
self.vote2 = MotionVote.objects.create(
|
|
|
|
user=self.user2, option=self.option, value="N", weight=Decimal(1)
|
|
|
|
)
|
2020-03-11 10:22:03 +01:00
|
|
|
self.poll.voted.add(self.user2)
|
2019-10-18 14:18:49 +02:00
|
|
|
|
|
|
|
def test_reset_poll(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-reset", args=[self.poll.pk]))
|
2019-11-12 18:30:26 +01:00
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
2019-10-18 14:18:49 +02:00
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertEqual(poll.get_votes().count(), 0)
|
|
|
|
self.assertEqual(poll.votesvalid, None)
|
|
|
|
self.assertEqual(poll.votesinvalid, None)
|
|
|
|
self.assertEqual(poll.votescast, None)
|
|
|
|
option = poll.options.get()
|
|
|
|
self.assertEqual(option.yes, Decimal("0"))
|
|
|
|
self.assertEqual(option.no, Decimal("0"))
|
|
|
|
self.assertEqual(option.abstain, Decimal("0"))
|
|
|
|
self.assertFalse(option.votes.exists())
|
|
|
|
|
2021-03-25 13:13:49 +01:00
|
|
|
def test_reset_pseudoanonymized(self):
|
|
|
|
self.poll.type = BasePoll.TYPE_NAMED
|
|
|
|
self.poll.is_pseudoanonymized = True
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-reset", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertFalse(poll.is_pseudoanonymized)
|
|
|
|
|
|
|
|
def test_reset_pseudoanonymous(self):
|
|
|
|
self.poll.type = BasePoll.TYPE_PSEUDOANONYMOUS
|
|
|
|
self.poll.is_pseudoanonymized = True
|
|
|
|
self.poll.save()
|
|
|
|
response = self.client.post(reverse("motionpoll-reset", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|
|
|
|
poll = MotionPoll.objects.get()
|
|
|
|
self.assertTrue(poll.is_pseudoanonymized)
|
|
|
|
|
2020-09-10 12:09:05 +02:00
|
|
|
|
|
|
|
class TestMotionPollWithVoteDelegationAutoupdate(TestCase):
|
|
|
|
def advancedSetUp(self):
|
2021-04-26 08:31:22 +02:00
|
|
|
"""Set up user -> other_user delegation."""
|
2020-09-10 12:09:05 +02:00
|
|
|
self.motion = Motion(
|
|
|
|
title="test_title_dL91JqhMTiQuQLSDRItZ",
|
|
|
|
text="test_text_R7nURdXKVEfEnnJBXJYa",
|
|
|
|
)
|
|
|
|
self.motion.save()
|
|
|
|
|
|
|
|
self.delegate_group = get_group_model().objects.get(pk=GROUP_DELEGATE_PK)
|
|
|
|
|
|
|
|
self.other_user, _ = self.create_user()
|
|
|
|
self.user, user_password = self.create_user()
|
|
|
|
self.user.groups.add(self.delegate_group)
|
|
|
|
self.user.is_present = True
|
|
|
|
self.user.vote_delegated_to = self.other_user
|
|
|
|
self.user.save()
|
|
|
|
|
|
|
|
self.user_client = APIClient()
|
|
|
|
self.user_client.login(username=self.user.username, password=user_password)
|
|
|
|
|
|
|
|
self.poll = MotionPoll.objects.create(
|
|
|
|
motion=self.motion,
|
|
|
|
title="test_title_Q3EuRaALSCCPJuQ2tMqj",
|
|
|
|
pollmethod="YNA",
|
|
|
|
type=BasePoll.TYPE_NAMED,
|
|
|
|
onehundred_percent_base="YN",
|
|
|
|
majority_method="simple",
|
|
|
|
)
|
|
|
|
self.poll.create_options()
|
|
|
|
self.poll.groups.add(self.delegate_group)
|
|
|
|
self.poll.save()
|
|
|
|
|
|
|
|
def test_start_poll(self):
|
|
|
|
response = self.client.post(reverse("motionpoll-start", args=[self.poll.pk]))
|
|
|
|
self.assertHttpStatusVerbose(response, status.HTTP_200_OK)
|