OpenSlides/server/tests/integration/motions/test_motions.py
FinnStutzenstein 2bcab5d098
Repository restructure
- moved all server related things into the folder `server`, so this
configuration is parallel to the client.
- All main "services" are now folders in the root directory
- Added Dockerfiles to each service (currently server and client)
- Added a docker compose configuration to start everything together.
Currently there are heavy dependencies into https://github.com/OpenSlides/openslides-docker-compose
- Resturctured the .gitignore. If someone needs something excluded,
please add it to the right section.
- Added initial build setup with Docker and docker-compose.
- removed setup.py. We won't deliver OpenSlides via pip anymore.
2020-08-21 08:11:13 +02:00

1027 lines
38 KiB
Python

import json
import pytest
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
from openslides.core.models import Tag
from openslides.motions.models import (
Category,
Motion,
MotionBlock,
MotionChangeRecommendation,
MotionComment,
MotionCommentSection,
MotionPoll,
Submitter,
Workflow,
)
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
from tests.count_queries import count_queries
from tests.test_case import TestCase
@pytest.mark.django_db(transaction=False)
def test_motion_db_queries():
"""
Tests that only the following db queries are done:
* 1 requests to get the list of all motions,
* 1 request to get the associated workflow
* 1 request for all motion comments
* 1 request for all motion comment sections required for the comments
* 1 request for all users required for the read_groups of the sections
* 1 request to get all amendments of all motions
* 1 request to get the agenda item,
* 1 request to get the list of speakers,
* 1 request to get the attachments,
* 1 request to get the tags,
* 2 requests to get the submitters and supporters,
* 1 request for change_recommendations.
Two comment sections are created and for each motions two comments.
"""
section1 = MotionCommentSection.objects.create(name="test_section")
section2 = MotionCommentSection.objects.create(name="test_section")
user1 = get_user_model().objects.create_user(
username="test_username_Iena7vahyaiphaangeaV",
password="test_password_oomie4jahNgook1ooDee",
)
user2 = get_user_model().objects.create_user(
username="test_username_ohj4eiN3ejali9ahng6e",
password="test_password_Coo3ong1cheeveiD3sho",
)
user3 = get_user_model().objects.create_user(
username="test_username_oe2Yei9Tho8see1Reija",
password="test_password_faij5aeBingaec5Jeila",
)
for index in range(10):
motion = Motion.objects.create(title=f"motion{index}")
motion.supporters.add(user1, user2)
Submitter.objects.add(user2, motion)
Submitter.objects.add(user3, motion)
MotionComment.objects.create(
comment="test_comment", motion=motion, section=section1
)
MotionComment.objects.create(
comment="test_comment2", motion=motion, section=section2
)
block = MotionBlock.objects.create(title=f"block_{index}")
motion.motion_block = block
category = Category.objects.create(name=f"category_{index}")
motion.category = category
motion.save()
# Create a poll:
poll = MotionPoll.objects.create(
motion=motion,
title="test_title_XeejaeFez3chahpei9qu",
pollmethod="YNA",
type=BasePoll.TYPE_NAMED,
)
poll.create_options()
assert count_queries(Motion.get_elements)() == 13
class CreateMotion(TestCase):
"""
Tests motion creation.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
def test_simple(self):
"""
Tests that a motion is created with a specific title and text.
The created motion should have an identifier and the admin user should
be the submitter.
"""
with self.assertNumQueries(54):
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_OoCoo3MeiT9li5Iengu9",
"text": "test_text_thuoz0iecheiheereiCi",
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
changed_autoupdate, deleted_autoupdate = self.get_last_autoupdate()
del changed_autoupdate["motions/motion:1"]["created"]
del changed_autoupdate["motions/motion:1"]["last_modified"]
self.assertEqual(
changed_autoupdate,
{
"agenda/list-of-speakers:1": {
"id": 1,
"title_information": {
"title": "test_title_OoCoo3MeiT9li5Iengu9",
"identifier": "1",
},
"speakers": [],
"closed": False,
"content_object": {"collection": "motions/motion", "id": 1},
},
"motions/motion:1": {
"id": 1,
"identifier": "1",
"title": "test_title_OoCoo3MeiT9li5Iengu9",
"text": "test_text_thuoz0iecheiheereiCi",
"amendment_paragraphs": None,
"amendments_id": [],
"modified_final_version": "",
"reason": "",
"parent_id": None,
"category_id": None,
"category_weight": 10000,
"comments": [],
"motion_block_id": None,
"origin": "",
"submitters": [
{"id": 1, "user_id": 1, "motion_id": 1, "weight": 1}
],
"supporters_id": [],
"state_id": 1,
"state_extension": None,
"state_restriction": [],
"statute_paragraph_id": None,
"workflow_id": 1,
"recommendation_id": None,
"recommendation_extension": None,
"tags_id": [],
"attachments_id": [],
"agenda_item_id": 1,
"list_of_speakers_id": 1,
"sort_parent_id": None,
"weight": 10000,
"change_recommendations_id": [],
},
"agenda/item:1": {
"id": 1,
"item_number": "",
"title_information": {
"title": "test_title_OoCoo3MeiT9li5Iengu9",
"identifier": "1",
},
"comment": None,
"closed": False,
"type": 3,
"is_internal": False,
"is_hidden": True,
"duration": None,
"content_object": {"collection": "motions/motion", "id": 1},
"weight": 10000,
"parent_id": None,
"level": 0,
"tags_id": [],
},
},
)
self.assertEqual(deleted_autoupdate, [])
self.assertEqual(motion.title, "test_title_OoCoo3MeiT9li5Iengu9")
self.assertEqual(motion.identifier, "1")
self.assertTrue(motion.submitters.exists())
self.assertEqual(motion.submitters.get().user.username, "admin")
def test_with_reason(self):
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_saib4hiHaifo9ohp9yie",
"text": "test_text_shahhie8Ej4mohvoorie",
"reason": "test_reason_Ou8GivahYivoh3phoh9c",
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(
Motion.objects.get().reason, "test_reason_Ou8GivahYivoh3phoh9c"
)
def test_without_data(self):
response = self.client.post(reverse("motion-list"), {})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertTrue("title" in response.data)
def test_without_text(self):
response = self.client.post(
reverse("motion-list"), {"title": "test_title_dlofp23m9O(ZD2d1lwHG"}
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
str(response.data["detail"][0]), "The text field may not be blank."
)
def test_with_category(self):
category = Category.objects.create(
name="test_category_name_CiengahzooH4ohxietha",
prefix="TEST_PREFIX_la0eadaewuec3seoxeiN",
)
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_Air0bahchaiph1ietoo2",
"text": "test_text_chaeF9wosh8OowazaiVu",
"category_id": category.pk,
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
self.assertEqual(motion.category, category)
self.assertEqual(motion.identifier, "TEST_PREFIX_la0eadaewuec3seoxeiN1")
def test_with_submitters(self):
submitter_1 = get_user_model().objects.create_user(
username="test_username_ooFe6aebei9ieQui2poo",
password="test_password_vie9saiQu5Aengoo9ku0",
)
submitter_2 = get_user_model().objects.create_user(
username="test_username_eeciengoc4aihie5eeSh",
password="test_password_peik2Eihu5oTh7siequi",
)
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_pha7moPh7quoth4paina",
"text": "test_text_YooGhae6tiangung5Rie",
"submitters_id": [submitter_1.pk, submitter_2.pk],
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
self.assertEqual(motion.submitters.count(), 2)
def test_with_one_supporter(self):
supporter = get_user_model().objects.create_user(
username="test_username_ahGhi4Quohyee7ohngie",
password="test_password_Nei6aeh8OhY8Aegh1ohX",
)
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_Oecee4Da2Mu9EY6Ui4mu",
"text": "test_text_FbhgnTFgkbjdmvcjbffg",
"supporters_id": [supporter.pk],
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
self.assertEqual(
motion.supporters.get().username, "test_username_ahGhi4Quohyee7ohngie"
)
def test_with_tag(self):
tag = Tag.objects.create(name="test_tag_iRee3kiecoos4rorohth")
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_Hahke4loos4eiduNiid9",
"text": "test_text_johcho0Ucaibiehieghe",
"tags_id": [tag.pk],
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
self.assertEqual(motion.tags.get().name, "test_tag_iRee3kiecoos4rorohth")
def test_with_workflow(self):
"""
Test to create a motion with a specific workflow.
"""
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_eemuR5hoo4ru2ahgh5EJ",
"text": "test_text_ohviePopahPhoili7yee",
"workflow_id": "2",
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Motion.objects.get().state.workflow_id, 2)
def test_non_admin(self):
"""
Test to create a motion by a delegate, non staff user.
"""
self.admin = get_user_model().objects.get(username="admin")
self.admin.groups.add(GROUP_DELEGATE_PK)
self.admin.groups.remove(GROUP_ADMIN_PK)
inform_changed_data(self.admin)
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_peiJozae0luew9EeL8bo",
"text": "test_text_eHohS8ohr5ahshoah8Oh",
},
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_amendment_motion(self):
"""
Test to create a motion with a parent motion as staff user.
"""
parent_motion = self.create_parent_motion()
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_doe93Jsjd2sW20dkSl20",
"text": "test_text_feS20SksD8D25skmwD25",
"parent_id": parent_motion.id,
},
)
created_motion = Motion.objects.get(pk=int(response.data["id"]))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(created_motion.parent, parent_motion)
def test_amendment_motion_parent_not_exist(self):
"""
Test to create an amendment motion with a non existing parent.
"""
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_gEjdkW93Wj23KS2s8dSe",
"text": "test_text_lfwLIC&AjfsaoijOEusa",
"parent_id": 100,
},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.data, {"detail": "The parent motion does not exist."})
def test_amendment_motion_non_admin(self):
"""
Test to create an amendment motion by a delegate. The parents
category should be also set on the new motion.
"""
parent_motion = self.create_parent_motion()
category = Category.objects.create(
name="test_category_name_Dslk3Fj8s8Ps36S3Kskw",
prefix="TEST_PREFIX_L23skfmlq3kslamslS39",
)
parent_motion.category = category
parent_motion.save()
self.admin = get_user_model().objects.get(username="admin")
self.admin.groups.add(GROUP_DELEGATE_PK)
self.admin.groups.remove(GROUP_ADMIN_PK)
inform_changed_data(self.admin)
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_fk3a0slalms47KSewnWG",
"text": "test_text_al3FMwSCNM31WOmw9ezx",
"parent_id": parent_motion.id,
},
)
created_motion = Motion.objects.get(pk=int(response.data["id"]))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(created_motion.parent, parent_motion)
self.assertEqual(created_motion.category, category)
def create_parent_motion(self):
"""
Returns a new created motion used for testing amendments.
"""
response = self.client.post(
reverse("motion-list"),
{
"title": "test_title_3leoeo2qac7830c92j9s",
"text": "test_text_9dm3ks9gDuW20Al38L9w",
},
)
return Motion.objects.get(pk=int(response.data["id"]))
class RetrieveMotion(TestCase):
"""
Tests retrieving a motion
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.motion = Motion(
title="test_title_uj5eeSiedohSh3ohyaaj",
text="test_text_ithohchaeThohmae5aug",
)
self.motion.save()
for index in range(10):
get_user_model().objects.create_user(
username=f"user_{index}", password="password"
)
def test_guest_state_with_restriction(self):
config["general_system_enable_anonymous"] = True
guest_client = APIClient()
state = self.motion.state
state.restriction = ["motions.can_manage"]
state.save()
# The cache has to be cleared, see:
# https://github.com/OpenSlides/OpenSlides/issues/3396
inform_changed_data(self.motion)
response = guest_client.get(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, 404)
def test_admin_state_with_restriction(self):
state = self.motion.state
state.restriction = ["motions.can_manage"]
state.save()
response = self.client.get(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_submitter_state_with_restriction(self):
state = self.motion.state
state.restriction = ["is_submitter"]
state.save()
user = get_user_model().objects.create_user(
username="username_ohS2opheikaSa5theijo",
password="password_kau4eequaisheeBateef",
)
Submitter.objects.add(user, self.motion)
submitter_client = APIClient()
submitter_client.force_login(user)
response = submitter_client.get(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_user_without_can_see_user_permission_to_see_motion_and_submitter_data(
self,
):
admin = get_user_model().objects.get(username="admin")
Submitter.objects.add(admin, self.motion)
group = get_group_model().objects.get(
pk=GROUP_DEFAULT_PK
) # Group with pk 1 is for anonymous and default users.
permission_string = "users.can_see_name"
app_label, codename = permission_string.split(".")
permission = group.permissions.get(
content_type__app_label=app_label, codename=codename
)
group.permissions.remove(permission)
config["general_system_enable_anonymous"] = True
guest_client = APIClient()
inform_changed_data(group)
inform_changed_data(self.motion)
response_1 = guest_client.get(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response_1.status_code, status.HTTP_200_OK)
submitter_id = response_1.data["submitters"][0]["user_id"]
response_2 = guest_client.get(reverse("user-detail", args=[submitter_id]))
self.assertEqual(response_2.status_code, status.HTTP_200_OK)
extra_user = get_user_model().objects.create_user(
username="username_wequePhieFoom0hai3wa",
password="password_ooth7taechai5Oocieya",
)
response_3 = guest_client.get(reverse("user-detail", args=[extra_user.pk]))
self.assertEqual(response_3.status_code, 404)
class UpdateMotion(TestCase):
"""
Tests updating motions.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.motion = Motion(
title="test_title_aeng7ahChie3waiR8xoh",
text="test_text_xeigheeha7thopubeu4U",
)
self.motion.save()
def test_simple_patch(self):
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
{"identifier": "test_identifier_jieseghohj7OoSah1Ko9"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
motion = Motion.objects.get()
self.assertAutoupdate(motion)
self.assertAutoupdate(motion.agenda_item)
self.assertAutoupdate(motion.list_of_speakers)
self.assertEqual(motion.title, "test_title_aeng7ahChie3waiR8xoh")
self.assertEqual(motion.identifier, "test_identifier_jieseghohj7OoSah1Ko9")
def test_patch_as_anonymous_without_manage_perms(self):
config["general_system_enable_anonymous"] = True
guest_client = APIClient()
response = guest_client.patch(
reverse("motion-detail", args=[self.motion.pk]),
{"identifier": "test_identifier_4g2jgj1wrnmvvIRhtqqPO84WD"},
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
motion = Motion.objects.get()
self.assertEqual(motion.identifier, "1")
def test_patch_empty_text(self):
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]), {"text": ""}
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
motion = Motion.objects.get()
self.assertEqual(motion.text, "test_text_xeigheeha7thopubeu4U")
def test_patch_amendment_paragraphs_no_manage_perms(self):
admin = get_user_model().objects.get(username="admin")
admin.groups.remove(GROUP_ADMIN_PK)
admin.groups.add(GROUP_DELEGATE_PK)
Submitter.objects.add(admin, self.motion)
self.motion.state.allow_submitter_edit = True
self.motion.state.save()
inform_changed_data(admin)
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
{"amendment_paragraphs": ["test_paragraph_39fo8qcpcaFMmjfaD2Lb"]},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
motion = Motion.objects.get()
self.assertTrue(isinstance(motion.amendment_paragraphs, list))
self.assertEqual(len(motion.amendment_paragraphs), 1)
self.assertEqual(
motion.amendment_paragraphs[0], "test_paragraph_39fo8qcpcaFMmjfaD2Lb"
)
self.assertEqual(motion.text, "")
def test_patch_workflow(self):
"""
Tests to only update the workflow of a motion.
"""
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]), {"workflow_id": "2"}
)
motion = Motion.objects.get()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(motion.title, "test_title_aeng7ahChie3waiR8xoh")
self.assertEqual(motion.workflow_id, 2)
def test_patch_category(self):
"""
Tests to only update the category of a motion. Expects the
category_weight to be resetted.
"""
category = Category.objects.create(
name="test_category_name_FE3jO(Fm83doqqlwcvlv",
prefix="test_prefix_w3ofg2mv79UGFqjk3f8h",
)
self.motion.category_weight = 1
self.motion.save()
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
{"category_id": category.pk},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
motion = Motion.objects.get()
self.assertEqual(motion.category, category)
self.assertEqual(motion.category_weight, 10000)
def test_patch_supporters(self):
supporter = get_user_model().objects.create_user(
username="test_username_ieB9eicah0uqu6Phoovo",
password="test_password_XaeTe3aesh8ohg6Cohwo",
)
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
json.dumps({"supporters_id": [supporter.pk]}),
content_type="application/json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
motion = Motion.objects.get()
self.assertEqual(motion.title, "test_title_aeng7ahChie3waiR8xoh")
self.assertEqual(
motion.supporters.get().username, "test_username_ieB9eicah0uqu6Phoovo"
)
def test_patch_supporters_non_manager(self):
non_admin = get_user_model().objects.create_user(
username="test_username_uqu6PhoovieB9eicah0o",
password="test_password_Xaesh8ohg6CoheTe3awo",
)
self.client.login(
username="test_username_uqu6PhoovieB9eicah0o",
password="test_password_Xaesh8ohg6CoheTe3awo",
)
motion = Motion.objects.get()
Submitter.objects.add(non_admin, self.motion)
motion.supporters.clear()
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
json.dumps({"supporters_id": [1]}),
content_type="application/json",
)
# Forbidden because of changed workflow state.
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_removal_of_supporters(self):
# No cache used here.
admin = get_user_model().objects.get(username="admin")
group_admin = admin.groups.get(name="Admin")
admin.groups.remove(group_admin)
Submitter.objects.add(admin, self.motion)
supporter = get_user_model().objects.create_user(
username="test_username_ahshi4oZin0OoSh9chee",
password="test_password_Sia8ahgeenixu5cei2Ib",
)
self.motion.supporters.add(supporter)
config["motions_remove_supporters"] = True
self.assertEqual(self.motion.supporters.count(), 1)
inform_changed_data((admin, self.motion))
response = self.client.patch(
reverse("motion-detail", args=[self.motion.pk]),
{"title": "new_title_ohph1aedie5Du8sai2ye"},
)
# Forbidden because of changed workflow state.
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
class DeleteMotion(TestCase):
"""
Tests deleting motions.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.admin = get_user_model().objects.get(username="admin")
self.motion = Motion(
title="test_title_acle3fa93l11lwlkcc31",
text="test_text_f390sjfyycj29ss56sro",
)
self.motion.save()
def test_simple_delete(self):
response = self.client.delete(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
motions = Motion.objects.count()
self.assertEqual(motions, 0)
def make_admin_delegate(self):
self.admin.groups.remove(GROUP_ADMIN_PK)
self.admin.groups.add(GROUP_DELEGATE_PK)
inform_changed_data(self.admin)
def put_motion_in_complex_workflow(self):
workflow = Workflow.objects.get(name="Complex Workflow")
self.motion.reset_state(workflow=workflow)
self.motion.save()
def test_delete_foreign_motion_as_delegate(self):
self.make_admin_delegate()
self.put_motion_in_complex_workflow()
response = self.client.delete(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_delete_own_motion_as_delegate(self):
self.make_admin_delegate()
self.put_motion_in_complex_workflow()
Submitter.objects.add(self.admin, self.motion)
response = self.client.delete(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
motions = Motion.objects.count()
self.assertEqual(motions, 0)
def test_delete_with_two_change_recommendations(self):
self.cr1 = MotionChangeRecommendation.objects.create(
motion=self.motion, internal=False, line_from=1, line_to=1
)
self.cr2 = MotionChangeRecommendation.objects.create(
motion=self.motion, internal=False, line_from=2, line_to=2
)
response = self.client.delete(reverse("motion-detail", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
motions = Motion.objects.count()
self.assertEqual(motions, 0)
class ManageMultipleSubmitters(TestCase):
"""
Tests adding and removing of submitters.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.admin = get_user_model().objects.get()
self.motion1 = Motion(
title="test_title_SlqfMw(waso0saWMPqcZ",
text="test_text_f30skclqS9wWF=xdfaSL",
)
self.motion1.save()
self.motion2 = Motion(
title="test_title_f>FLEim38MC2m9PFp2jG",
text="test_text_kg39KFGm,ao)22FK9lLu",
)
self.motion2.save()
def test_set_submitters(self):
response = self.client.post(
reverse("motion-manage-multiple-submitters"),
json.dumps(
{
"motions": [
{"id": self.motion1.id, "submitters": [self.admin.pk]},
{"id": self.motion2.id, "submitters": [self.admin.pk]},
]
}
),
content_type="application/json",
)
self.assertEqual(response.status_code, 200)
self.assertEqual(self.motion1.submitters.count(), 1)
self.assertEqual(self.motion2.submitters.count(), 1)
self.assertEqual(
self.motion1.submitters.get().user.pk, self.motion2.submitters.get().user.pk
)
def test_non_existing_user(self):
response = self.client.post(
reverse("motion-manage-multiple-submitters"),
{"motions": [{"id": self.motion1.id, "submitters": [1337]}]},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(self.motion1.submitters.count(), 0)
def test_add_user_no_data(self):
response = self.client.post(reverse("motion-manage-multiple-submitters"))
self.assertEqual(response.status_code, 400)
self.assertEqual(self.motion1.submitters.count(), 0)
self.assertEqual(self.motion2.submitters.count(), 0)
def test_add_user_invalid_data(self):
response = self.client.post(
reverse("motion-manage-multiple-submitters"), {"motions": ["invalid_str"]}
)
self.assertEqual(response.status_code, 400)
self.assertEqual(self.motion1.submitters.count(), 0)
self.assertEqual(self.motion2.submitters.count(), 0)
def test_add_without_permission(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)
response = self.client.post(
reverse("motion-manage-multiple-submitters"),
{"motions": [{"id": self.motion1.id, "submitters": [self.admin.pk]}]},
)
self.assertEqual(response.status_code, 403)
self.assertEqual(self.motion1.submitters.count(), 0)
self.assertEqual(self.motion2.submitters.count(), 0)
class SupportMotion(TestCase):
"""
Tests supporting a motion.
"""
def setUp(self):
self.admin = get_user_model().objects.get(username="admin")
self.admin.groups.add(GROUP_DELEGATE_PK)
inform_changed_data(self.admin)
self.client.login(username="admin", password="admin")
self.motion = Motion(
title="test_title_chee7ahCha6bingaew4e",
text="test_text_birah1theL9ooseeFaip",
)
self.motion.save()
def test_support(self):
config["motions_min_supporters"] = 1
response = self.client.post(reverse("motion-support", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data, {"detail": "You have supported this motion successfully."}
)
def test_unsupport(self):
config["motions_min_supporters"] = 1
self.motion.supporters.add(self.admin)
response = self.client.delete(reverse("motion-support", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data, {"detail": "You have unsupported this motion successfully."}
)
class SetState(TestCase):
"""
Tests setting a state.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.motion = Motion(
title="test_title_iac4ohquie9Ku6othieC",
text="test_text_Xohphei6Oobee0Evooyu",
)
self.motion.save()
self.state_id_accepted = 2 # This should be the id of the state 'accepted'.
def test_set_state(self):
response = self.client.put(
reverse("motion-set-state", args=[self.motion.pk]),
{"state": self.state_id_accepted},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data, {"detail": "The state of the motion was set to accepted."}
)
self.assertEqual(Motion.objects.get(pk=self.motion.pk).state.name, "accepted")
def test_set_state_with_string(self):
# Using a string is not allowed even if it is the correct name of the state.
response = self.client.put(
reverse("motion-set-state", args=[self.motion.pk]), {"state": "accepted"}
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"detail": "Invalid data. State must be an integer."}
)
def test_set_unknown_state(self):
invalid_state_id = 0
response = self.client.put(
reverse("motion-set-state", args=[self.motion.pk]),
{"state": invalid_state_id},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data,
{
"detail": "You can not set the state to {0}.",
"args": [str(invalid_state_id)],
},
)
def test_reset(self):
self.motion.set_state(self.state_id_accepted)
self.motion.save()
response = self.client.put(reverse("motion-set-state", args=[self.motion.pk]))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data, {"detail": "The state of the motion was set to submitted."}
)
self.assertEqual(Motion.objects.get(pk=self.motion.pk).state.name, "submitted")
class SetRecommendation(TestCase):
"""
Tests setting a recommendation.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.motion = Motion(
title="test_title_ahfooT5leilahcohJ2uz",
text="test_text_enoogh7OhPoo6eohoCus",
)
self.motion.save()
self.state_id_accepted = 2 # This should be the id of the state 'accepted'.
def test_set_recommendation(self):
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": self.state_id_accepted},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data,
{
"detail": "The recommendation of the motion was set to {0}.",
"args": ["Acceptance"],
},
)
self.assertEqual(
Motion.objects.get(pk=self.motion.pk).recommendation.name, "accepted"
)
def test_set_state_with_string(self):
# Using a string is not allowed even if it is the correct name of the state.
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": "accepted"},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data,
{"detail": "Invalid data. Recommendation must be an integer."},
)
def test_set_unknown_recommendation(self):
invalid_state_id = 0
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": invalid_state_id},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data,
{
"detail": "You can not set the recommendation to {0}.",
"args": [str(invalid_state_id)],
},
)
def test_set_invalid_recommendation(self):
# This is a valid state id, but this state is not recommendable because it belongs to a different workflow.
invalid_state_id = 6 # State 'permitted'
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": invalid_state_id},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data,
{
"detail": "You can not set the recommendation to {0}.",
"args": [str(invalid_state_id)],
},
)
def test_set_invalid_recommendation_2(self):
# This is a valid state id, but this state is not recommendable because it has not recommendation label
invalid_state_id = 1 # State 'submitted'
self.motion.set_state(self.state_id_accepted)
self.motion.save()
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": invalid_state_id},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data,
{
"detail": "You can not set the recommendation to {0}.",
"args": [str(invalid_state_id)],
},
)
def test_reset(self):
self.motion.set_recommendation(self.state_id_accepted)
self.motion.save()
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk])
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data,
{
"detail": "The recommendation of the motion was set to {0}.",
"args": ["None"],
},
)
self.assertTrue(Motion.objects.get(pk=self.motion.pk).recommendation is None)
def test_set_recommendation_to_current_state(self):
self.motion.set_state(self.state_id_accepted)
self.motion.save()
response = self.client.put(
reverse("motion-set-recommendation", args=[self.motion.pk]),
{"recommendation": self.state_id_accepted},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data,
{
"detail": "The recommendation of the motion was set to {0}.",
"args": ["Acceptance"],
},
)
self.assertEqual(
Motion.objects.get(pk=self.motion.pk).recommendation.name, "accepted"
)