OpenSlides/openslides/motions/projector.py

324 lines
11 KiB
Python
Raw Normal View History

import re
2018-12-23 11:05:38 +01:00
from typing import Any, Dict
from ..users.projector import get_user_name
from ..utils.projector import (
AllData,
ProjectorElementException,
get_config,
register_projector_slide,
)
motion_placeholder_regex = re.compile(r"\[motion:(\d+)\]")
2018-12-23 11:05:38 +01:00
# Important: All functions have to be prune. This means, that thay can only
# access the data, that they get as argument and do not have any
# side effects.
async def get_state(
2019-01-19 21:36:30 +01:00
all_data: AllData, motion: Dict[str, Any], state_id: int
2018-12-23 11:05:38 +01:00
) -> Dict[str, Any]:
2019-01-19 21:36:30 +01:00
"""
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
raise ProjectorElementException(
f"motion {motion['id']} can not be on the state with id {state_id}"
)
2019-01-19 21:36:30 +01:00
async def get_amendment_merge_into_motion_diff(all_data, motion, amendment):
"""
2019-03-09 15:00:03 +01:00
HINT: This implementation should be consistent to showInDiffView() in ViewMotionAmendedParagraph.ts
"""
if amendment["state_id"] is None:
return 0
state = await get_state(all_data, motion, amendment["state_id"])
2019-03-09 15:00:03 +01:00
if state["merge_amendment_into_final"] == -1:
return 0
if state["merge_amendment_into_final"] == 1:
return 1
if amendment["recommendation_id"] is None:
return 0
recommendation = await get_state(all_data, motion, amendment["recommendation_id"])
2019-03-09 15:00:03 +01:00
if recommendation["merge_amendment_into_final"] == 1:
return 1
return 0
async def get_amendment_merge_into_motion_final(all_data, motion, amendment):
2019-03-09 15:00:03 +01:00
"""
HINT: This implementation should be consistent to showInFinalView() in ViewMotionAmendedParagraph.ts
"""
if amendment["state_id"] is None:
return 0
state = await get_state(all_data, motion, amendment["state_id"])
2019-03-09 15:00:03 +01:00
if state["merge_amendment_into_final"] == 1:
return 1
return 0
async def get_amendments_for_motion(motion, all_data):
amendment_data = []
for amendment_id, amendment in all_data["motions/motion"].items():
if amendment["parent_id"] == motion["id"]:
merge_amendment_into_final = await get_amendment_merge_into_motion_final(
2019-03-09 15:00:03 +01:00
all_data, motion, amendment
)
merge_amendment_into_diff = await get_amendment_merge_into_motion_diff(
all_data, motion, amendment
)
amendment_data.append(
{
"id": amendment["id"],
"identifier": amendment["identifier"],
"title": amendment["title"],
"amendment_paragraphs": amendment["amendment_paragraphs"],
2019-03-09 15:00:03 +01:00
"merge_amendment_into_diff": merge_amendment_into_diff,
"merge_amendment_into_final": merge_amendment_into_final,
}
)
return amendment_data
async def get_amendment_base_motion(amendment, all_data):
try:
motion = all_data["motions/motion"][amendment["parent_id"]]
except KeyError:
motion_id = amendment["parent_id"]
raise ProjectorElementException(f"motion with id {motion_id} does not exist")
return {
"identifier": motion["identifier"],
"title": motion["title"],
"text": motion["text"],
}
async def get_amendment_base_statute(amendment, all_data):
try:
statute = all_data["motions/statute-paragraph"][
amendment["statute_paragraph_id"]
]
except KeyError:
statute_id = amendment["statute_paragraph_id"]
raise ProjectorElementException(f"statute with id {statute_id} does not exist")
return {"title": statute["title"], "text": statute["text"]}
2019-01-19 21:36:30 +01:00
async def extend_reference_motion_dict(
all_data: AllData,
recommendation: str,
referenced_motions: Dict[int, Dict[str, str]],
) -> None:
"""
Extends a dict of motion ids mapped to their title information.
The client can replace the placeholders in the recommendation correctly.
"""
# Collect all meantioned motions via [motion:<id>]
referenced_ids = [
int(id) for id in motion_placeholder_regex.findall(recommendation)
]
for id in referenced_ids:
# Put every referenced motion into the referenced_motions dict
if id not in referenced_motions and id in all_data["motions/motion"]:
referenced_motions[id] = {
"title": all_data["motions/motion"][id]["title"],
"identifier": all_data["motions/motion"][id]["identifier"],
}
async def motion_slide(
2019-02-21 14:40:07 +01:00
all_data: AllData, element: Dict[str, Any], projector_id: int
) -> Dict[str, Any]:
"""
2018-12-23 11:05:38 +01:00
Motion slide.
2019-01-19 21:36:30 +01:00
The returned dict can contain the following fields:
* identifier
* title
* text
* amendment_paragraphs
* is_child
* show_meta_box
* reason
* modified_final_version
* recommendation
* recommendation_extension
* recommender
* change_recommendations
2019-01-19 21:36:30 +01:00
* submitter
"""
mode = element.get(
"mode", await get_config(all_data, "motions_recommendation_text_mode")
)
2019-01-19 21:36:30 +01:00
motion_id = element.get("id")
2019-01-06 16:22:33 +01:00
2019-01-19 21:36:30 +01:00
if motion_id is None:
2019-02-15 12:01:16 +01:00
raise ProjectorElementException("id is required for motion slide")
2019-01-19 21:36:30 +01:00
try:
motion = all_data["motions/motion"][motion_id]
except KeyError:
raise ProjectorElementException(f"motion with id {motion_id} does not exist")
2019-01-19 21:36:30 +01:00
show_meta_box = not await get_config(
all_data, "motions_disable_sidebox_on_projector"
)
line_length = await get_config(all_data, "motions_line_length")
line_numbering_mode = await get_config(all_data, "motions_default_line_numbering")
motions_preamble = await get_config(all_data, "motions_preamble")
if motion["statute_paragraph_id"]:
change_recommendations = [] # type: ignore
amendments = [] # type: ignore
base_motion = None
base_statute = await get_amendment_base_statute(motion, all_data)
elif bool(motion["parent_id"]) and motion["amendment_paragraphs"]:
change_recommendations = []
amendments = []
base_motion = await get_amendment_base_motion(motion, all_data)
base_statute = None
else:
change_recommendations = list(
filter(
lambda reco: reco["internal"] is False, motion["change_recommendations"]
)
)
amendments = await get_amendments_for_motion(motion, all_data)
base_motion = None
base_statute = None
2019-01-19 21:36:30 +01:00
return_value = {
"identifier": motion["identifier"],
"title": motion["title"],
"preamble": motions_preamble,
2019-01-19 21:36:30 +01:00
"text": motion["text"],
"amendment_paragraphs": motion["amendment_paragraphs"],
"base_motion": base_motion,
"base_statute": base_statute,
2019-01-19 21:36:30 +01:00
"is_child": bool(motion["parent_id"]),
"show_meta_box": show_meta_box,
"change_recommendations": change_recommendations,
"amendments": amendments,
"line_length": line_length,
"line_numbering_mode": line_numbering_mode,
2019-01-19 21:36:30 +01:00
}
if not await get_config(all_data, "motions_disable_reason_on_projector"):
2019-01-19 21:36:30 +01:00
return_value["reason"] = motion["reason"]
2019-01-19 21:36:30 +01:00
if mode == "final":
return_value["modified_final_version"] = motion["modified_final_version"]
if show_meta_box:
if (
not await get_config(
all_data, "motions_disable_recommendation_on_projector"
)
2019-01-19 21:36:30 +01:00
and motion["recommendation_id"]
):
recommendation_state = await get_state(
all_data, motion, motion["recommendation_id"]
)
return_value["recommendation"] = recommendation_state[
"recommendation_label"
2019-01-19 21:36:30 +01:00
]
if recommendation_state["show_recommendation_extension_field"]:
recommendation_extension = motion["recommendation_extension"]
# All title information for referenced motions in the recommendation
referenced_motions: Dict[int, Dict[str, str]] = {}
await extend_reference_motion_dict(
all_data, recommendation_extension, referenced_motions
)
return_value["recommendation_extension"] = recommendation_extension
return_value["referenced_motions"] = referenced_motions
return_value["recommender"] = await get_config(
all_data, "motions_recommendations_by"
)
2019-01-19 21:36:30 +01:00
return_value["submitter"] = [
await get_user_name(all_data, submitter["user_id"])
for submitter in sorted(
motion["submitters"], key=lambda submitter: submitter["weight"]
)
2019-01-19 21:36:30 +01:00
]
return return_value
async def motion_block_slide(
2019-02-21 14:40:07 +01:00
all_data: AllData, element: Dict[str, Any], projector_id: int
) -> Dict[str, Any]:
2018-12-23 11:05:38 +01:00
"""
2019-02-21 12:34:13 +01:00
Motion block slide.
2018-12-23 11:05:38 +01:00
"""
2019-02-21 12:34:13 +01:00
motion_block_id = element.get("id")
if motion_block_id is None:
raise ProjectorElementException("id is required for motion block slide")
try:
motion_block = all_data["motions/motion-block"][motion_block_id]
except KeyError:
raise ProjectorElementException(
f"motion block with id {motion_block_id} does not exist"
)
# All motions in this motion block
2019-02-21 12:34:13 +01:00
motions = []
# All title information for referenced motions in the recommendation
referenced_motions: Dict[int, Dict[str, str]] = {}
# Search motions.
2019-02-21 12:34:13 +01:00
for motion in all_data["motions/motion"].values():
if motion["motion_block_id"] == motion_block_id:
motion_object = {
"title": motion["title"],
"identifier": motion["identifier"],
}
recommendation_id = motion["recommendation_id"]
if recommendation_id is not None:
recommendation = await get_state(
2019-02-21 12:34:13 +01:00
all_data, motion, motion["recommendation_id"]
)
motion_object["recommendation"] = {
2019-02-21 15:06:14 +01:00
"name": recommendation["recommendation_label"],
2019-02-21 12:34:13 +01:00
"css_class": recommendation["css_class"],
}
if recommendation["show_recommendation_extension_field"]:
recommendation_extension = motion["recommendation_extension"]
await extend_reference_motion_dict(
all_data, recommendation_extension, referenced_motions
)
motion_object["recommendation_extension"] = recommendation_extension
2019-02-21 12:34:13 +01:00
motions.append(motion_object)
return {
"title": motion_block["title"],
"motions": motions,
"referenced_motions": referenced_motions,
}
def register_projector_slides() -> None:
register_projector_slide("motions/motion", motion_slide)
register_projector_slide("motions/motion-block", motion_block_slide)