Merge pull request #4152 from ostcar/new_projector_iv_motion_slide
New projector IV
This commit is contained in:
commit
1b3c0b4cee
@ -507,9 +507,11 @@ class Motion(RESTModelMixin, models.Model):
|
|||||||
"""
|
"""
|
||||||
if self.recommendation is not None:
|
if self.recommendation is not None:
|
||||||
self.set_state(self.recommendation)
|
self.set_state(self.recommendation)
|
||||||
if (self.recommendation_extension is not None
|
if (
|
||||||
|
self.recommendation_extension is not None
|
||||||
and self.state.show_state_extension_field
|
and self.state.show_state_extension_field
|
||||||
and self.recommendation.show_recommendation_extension_field):
|
and self.recommendation.show_recommendation_extension_field
|
||||||
|
):
|
||||||
self.state_extension = self.recommendation_extension
|
self.state_extension = self.recommendation_extension
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
from ..utils.projector import register_projector_element
|
from ..utils.projector import AllData, get_config, get_user, register_projector_element
|
||||||
|
|
||||||
|
|
||||||
# Important: All functions have to be prune. This means, that thay can only
|
# Important: All functions have to be prune. This means, that thay can only
|
||||||
@ -9,18 +9,105 @@ from ..utils.projector import register_projector_element
|
|||||||
# to be fast!
|
# to be fast!
|
||||||
|
|
||||||
|
|
||||||
def motion(
|
def get_state(
|
||||||
element: Dict[str, Any], all_data: Dict[str, Dict[int, Dict[str, Any]]]
|
all_data: AllData, motion: Dict[str, Any], state_id: int
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Returns a state element from one motion.
|
||||||
|
|
||||||
|
Returns an error if the state_id does not exist for the workflow in the motion.
|
||||||
|
"""
|
||||||
|
states = all_data["motions/workflow"][motion["workflow_id"]]["states"]
|
||||||
|
for state in states:
|
||||||
|
if state["id"] == state_id:
|
||||||
|
return state
|
||||||
|
return {"error": f"motion {motion['id']} can not have to id {state_id}"}
|
||||||
|
|
||||||
|
|
||||||
|
def motion_slide(element: Dict[str, Any], all_data: AllData) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Motion slide.
|
Motion slide.
|
||||||
|
|
||||||
|
The returned dict can contain the following fields:
|
||||||
|
* identifier
|
||||||
|
* title
|
||||||
|
* text
|
||||||
|
* amendment_paragraphs
|
||||||
|
* is_child
|
||||||
|
* show_meta_box
|
||||||
|
* reason
|
||||||
|
* modified_final_version
|
||||||
|
* state
|
||||||
|
* state_extension
|
||||||
|
* recommendation
|
||||||
|
* recommendation_extension
|
||||||
|
* submitter
|
||||||
|
* poll
|
||||||
"""
|
"""
|
||||||
return {"error": "TODO", "some_key": "another_value"}
|
mode = element.get("mode")
|
||||||
|
motion_id = element.get("id")
|
||||||
|
|
||||||
|
if motion_id is None:
|
||||||
|
return {"error": "id is required for motion slide"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
motion = all_data["motions/motion"][motion_id]
|
||||||
|
except KeyError:
|
||||||
|
return {"error": f"motion with id {motion_id} does not exist"}
|
||||||
|
|
||||||
|
show_meta_box = not get_config(all_data, "motions_disable_sidebox_on_projector")
|
||||||
|
|
||||||
|
return_value = {
|
||||||
|
"identifier": motion["identifier"],
|
||||||
|
"title": motion["title"],
|
||||||
|
"text": motion["text"],
|
||||||
|
"amendment_paragraphs": motion["amendment_paragraphs"],
|
||||||
|
"is_child": bool(motion["parent_id"]),
|
||||||
|
"show_meta_box": show_meta_box,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not get_config(all_data, "motions_disable_reason_on_projector"):
|
||||||
|
return_value["reason"] = motion["reason"]
|
||||||
|
if mode == "final":
|
||||||
|
return_value["modified_final_version"] = motion["modified_final_version"]
|
||||||
|
|
||||||
|
if show_meta_box:
|
||||||
|
state = get_state(all_data, motion, motion["state_id"])
|
||||||
|
if state.get("error"):
|
||||||
|
return state
|
||||||
|
|
||||||
|
return_value["state"] = state["name"]
|
||||||
|
return_value["state_extension"] = motion["state_extension"]
|
||||||
|
|
||||||
|
if (
|
||||||
|
not get_config(all_data, "motions_disable_recommendation_on_projector")
|
||||||
|
and motion["recommendation_id"]
|
||||||
|
):
|
||||||
|
return_value["recommendation"] = all_data[
|
||||||
|
"motions/motion-change-recommendation"
|
||||||
|
][motion["recommendation_id"]]["text"]
|
||||||
|
return_value["recommendation_extension"] = motion[
|
||||||
|
"recommendation_extension"
|
||||||
|
]
|
||||||
|
|
||||||
|
return_value["submitter"] = [
|
||||||
|
get_user(all_data, submitter["user_id"])
|
||||||
|
for submitter in motion["submitters"]
|
||||||
|
]
|
||||||
|
|
||||||
|
for poll in motion["polls"][::-1]:
|
||||||
|
if poll["has_votes"]:
|
||||||
|
return_value["poll"] = {
|
||||||
|
"yes": poll["yes"],
|
||||||
|
"no": poll["no"],
|
||||||
|
"abstain": poll["abstain"],
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
def motion_block(
|
def motion_block(element: Dict[str, Any], all_data: AllData) -> Dict[str, Any]:
|
||||||
element: Dict[str, Any], all_data: Dict[str, Dict[int, Dict[str, Any]]]
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
"""
|
"""
|
||||||
Motion slide.
|
Motion slide.
|
||||||
"""
|
"""
|
||||||
@ -28,5 +115,5 @@ def motion_block(
|
|||||||
|
|
||||||
|
|
||||||
def register_projector_elements() -> None:
|
def register_projector_elements() -> None:
|
||||||
register_projector_element("motions/motion", motion)
|
register_projector_element("motions/motion", motion_slide)
|
||||||
register_projector_element("motions/motion-block", motion_block)
|
register_projector_element("motions/motion-block", motion_block)
|
||||||
|
@ -92,3 +92,15 @@ def get_config(all_data: AllData, key: str) -> Any:
|
|||||||
return all_data[config.get_collection_string()][config.get_key_to_id()[key]][
|
return all_data[config.get_collection_string()][config.get_key_to_id()[key]][
|
||||||
"value"
|
"value"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_user(all_data: AllData, user_id: int) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Returns the value of a user to show his name.
|
||||||
|
"""
|
||||||
|
user = all_data["users/user"][user_id]
|
||||||
|
return {
|
||||||
|
"title": user["title"],
|
||||||
|
"first_name": user["first_name"],
|
||||||
|
"last_name": user["last_name"],
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ from django.test.utils import CaptureQueriesContext
|
|||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
from openslides.core.models import Projector
|
from openslides.core.models import Projector
|
||||||
from openslides.users.models import User
|
from openslides.users.models import User
|
||||||
from openslides.utils.projector import get_config, register_projector_element
|
from openslides.utils.projector import AllData, get_config, register_projector_element
|
||||||
|
|
||||||
|
|
||||||
class TConfig:
|
class TConfig:
|
||||||
@ -90,18 +90,14 @@ class TProjector:
|
|||||||
return elements
|
return elements
|
||||||
|
|
||||||
|
|
||||||
def slide1(
|
def slide1(element: Dict[str, Any], all_data: AllData) -> Dict[str, Any]:
|
||||||
config: Dict[str, Any], all_data: Dict[str, Dict[int, Dict[str, Any]]]
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
"""
|
"""
|
||||||
Slide that shows the general_event_name.
|
Slide that shows the general_event_name.
|
||||||
"""
|
"""
|
||||||
return {"name": "slide1", "event_name": get_config(all_data, "general_event_name")}
|
return {"name": "slide1", "event_name": get_config(all_data, "general_event_name")}
|
||||||
|
|
||||||
|
|
||||||
def slide2(
|
def slide2(element: Dict[str, Any], all_data: AllData) -> Dict[str, Any]:
|
||||||
config: Dict[str, Any], all_data: Dict[str, Dict[int, Dict[str, Any]]]
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
return {"name": "slide2"}
|
return {"name": "slide2"}
|
||||||
|
|
||||||
|
|
||||||
@ -121,3 +117,19 @@ def count_queries(func, *args, **kwargs) -> int:
|
|||||||
|
|
||||||
print(f"{len(context)} queries executed\nCaptured queries were:\n{queries}")
|
print(f"{len(context)} queries executed\nCaptured queries were:\n{queries}")
|
||||||
return len(context)
|
return len(context)
|
||||||
|
|
||||||
|
|
||||||
|
def all_data_config() -> AllData:
|
||||||
|
return {
|
||||||
|
TConfig().get_collection_string(): {
|
||||||
|
element["id"]: element for element in TConfig().get_elements()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def all_data_users() -> AllData:
|
||||||
|
return {
|
||||||
|
TUser().get_collection_string(): {
|
||||||
|
element["id"]: element for element in TUser().get_elements()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
173
tests/unit/motions/test_projector.py
Normal file
173
tests/unit/motions/test_projector.py
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openslides.motions import projector
|
||||||
|
|
||||||
|
from ...integration.helpers import all_data_config, all_data_users
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def all_data():
|
||||||
|
return_value = all_data_config()
|
||||||
|
return_value.update(all_data_users())
|
||||||
|
return_value["motions/motion"] = {
|
||||||
|
1: {
|
||||||
|
"id": 1,
|
||||||
|
"identifier": "4",
|
||||||
|
"title": "12345",
|
||||||
|
"text": "motion text",
|
||||||
|
"amendment_paragraphs": None,
|
||||||
|
"modified_final_version": "",
|
||||||
|
"reason": "",
|
||||||
|
"parent_id": None,
|
||||||
|
"category_id": None,
|
||||||
|
"comments": [],
|
||||||
|
"motion_block_id": None,
|
||||||
|
"origin": "",
|
||||||
|
"submitters": [{"id": 4, "user_id": 1, "motion_id": 1, "weight": 1}],
|
||||||
|
"supporters_id": [],
|
||||||
|
"state_id": 1,
|
||||||
|
"state_extension": None,
|
||||||
|
"state_required_permission_to_see": "",
|
||||||
|
"statute_paragraph_id": None,
|
||||||
|
"workflow_id": 1,
|
||||||
|
"recommendation_id": None,
|
||||||
|
"recommendation_extension": None,
|
||||||
|
"tags_id": [],
|
||||||
|
"attachments_id": [],
|
||||||
|
"polls": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"motion_id": 4,
|
||||||
|
"yes": "10.000000",
|
||||||
|
"no": "-1.000000",
|
||||||
|
"abstain": "20.000000",
|
||||||
|
"votesvalid": "11.000000",
|
||||||
|
"votesinvalid": "2.000000",
|
||||||
|
"votescast": "30.000000",
|
||||||
|
"has_votes": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"agenda_item_id": 4,
|
||||||
|
"log_messages": [
|
||||||
|
{
|
||||||
|
"message_list": "['Vote updated']",
|
||||||
|
"person_id": 1,
|
||||||
|
"time": "2019-01-19T22:15:53.291123+01:00",
|
||||||
|
"message": "Jan. 19, 2019, 10:15 p.m. Vote updated by Administrator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"message_list": "['Vote created']",
|
||||||
|
"person_id": 1,
|
||||||
|
"time": "2019-01-19T22:15:37.446262+01:00",
|
||||||
|
"message": "Jan. 19, 2019, 10:15 p.m. Vote created by Administrator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"message_list": "['Motion created']",
|
||||||
|
"person_id": 1,
|
||||||
|
"time": "2019-01-19T18:37:34.833749+01:00",
|
||||||
|
"message": "Jan. 19, 2019, 6:37 p.m. Motion created by Administrator",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"sort_parent_id": None,
|
||||||
|
"weight": 10000,
|
||||||
|
"created": "2019-01-19T18:37:34.741336+01:00",
|
||||||
|
"last_modified": "2019-01-19T18:37:34.741368+01:00",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return_value["motions/workflow"] = {
|
||||||
|
1: {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Simple Workflow",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "submitted",
|
||||||
|
"recommendation_label": None,
|
||||||
|
"css_class": "primary",
|
||||||
|
"required_permission_to_see": "",
|
||||||
|
"allow_support": True,
|
||||||
|
"allow_create_poll": True,
|
||||||
|
"allow_submitter_edit": True,
|
||||||
|
"dont_set_identifier": False,
|
||||||
|
"show_state_extension_field": False,
|
||||||
|
"merge_amendment_into_final": 0,
|
||||||
|
"show_recommendation_extension_field": False,
|
||||||
|
"next_states_id": [2, 3, 4],
|
||||||
|
"workflow_id": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "accepted",
|
||||||
|
"recommendation_label": "Acceptance",
|
||||||
|
"css_class": "success",
|
||||||
|
"required_permission_to_see": "",
|
||||||
|
"allow_support": False,
|
||||||
|
"allow_create_poll": False,
|
||||||
|
"allow_submitter_edit": False,
|
||||||
|
"dont_set_identifier": False,
|
||||||
|
"show_state_extension_field": False,
|
||||||
|
"merge_amendment_into_final": 1,
|
||||||
|
"show_recommendation_extension_field": False,
|
||||||
|
"next_states_id": [],
|
||||||
|
"workflow_id": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "rejected",
|
||||||
|
"recommendation_label": "Rejection",
|
||||||
|
"css_class": "danger",
|
||||||
|
"required_permission_to_see": "",
|
||||||
|
"allow_support": False,
|
||||||
|
"allow_create_poll": False,
|
||||||
|
"allow_submitter_edit": False,
|
||||||
|
"dont_set_identifier": False,
|
||||||
|
"show_state_extension_field": False,
|
||||||
|
"merge_amendment_into_final": -1,
|
||||||
|
"show_recommendation_extension_field": False,
|
||||||
|
"next_states_id": [],
|
||||||
|
"workflow_id": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "not decided",
|
||||||
|
"recommendation_label": "No decision",
|
||||||
|
"css_class": "default",
|
||||||
|
"required_permission_to_see": "",
|
||||||
|
"allow_support": False,
|
||||||
|
"allow_create_poll": False,
|
||||||
|
"allow_submitter_edit": False,
|
||||||
|
"dont_set_identifier": False,
|
||||||
|
"show_state_extension_field": False,
|
||||||
|
"merge_amendment_into_final": -1,
|
||||||
|
"show_recommendation_extension_field": False,
|
||||||
|
"next_states_id": [],
|
||||||
|
"workflow_id": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"first_state_id": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return_value["motions/motion-change-recommendation"] = {}
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
def test_motion_slide(all_data):
|
||||||
|
element: Dict[str, Any] = {"id": 1}
|
||||||
|
|
||||||
|
data = projector.motion_slide(element, all_data)
|
||||||
|
|
||||||
|
assert data == {
|
||||||
|
"identifier": "4",
|
||||||
|
"title": "12345",
|
||||||
|
"text": "motion text",
|
||||||
|
"amendment_paragraphs": None,
|
||||||
|
"is_child": False,
|
||||||
|
"show_meta_box": True,
|
||||||
|
"reason": "",
|
||||||
|
"state": "submitted",
|
||||||
|
"state_extension": None,
|
||||||
|
"submitter": [{"first_name": "", "last_name": "Administrator", "title": ""}],
|
||||||
|
"poll": {"yes": "10.000000", "no": "-1.000000", "abstain": "20.000000"},
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user