Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement motion_change_recommendation creation in motion forward #2549

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/actions/motion.create_forwarded.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use_original_submitter: boolean;
use_original_number: boolean;
with_amendments: boolean;
with_change_recommendations: boolean;
}
```

Expand All @@ -35,6 +36,8 @@ The three boolean flags for extra rules will be applied to the amendments as wel

If the forwarded amendments have amendments themselves, those will also be treated the same way

If `with_change_recommendations` is set to True, all change recommendations of the motion will be copied to the target meeting and connected to the newly forwarded lead motion. They will not have any reference to the original recommendation afterwards.

### Forwarding tree fields

* `all_origin_ids` of the newly created motion must be set to `all_origin_ids` of the origin motion plus the given `origin_id`. It is important that the id is appended at the end of the list, since the order of this field represents the order of the tree in case a motion of the tree is deleted.
Expand Down
1 change: 1 addition & 0 deletions docs/actions/motion.create_forwarded_amendment.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
amendment_paragraphs: JSON
use_original_submitter: boolean;
use_original_number: boolean;
with_change_recommendations: boolean;
}
```

Expand Down
2 changes: 1 addition & 1 deletion global/meta
Submodule meta updated 0 files
24 changes: 24 additions & 0 deletions openslides_backend/action/actions/motion/base_create_forwarded.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ....shared.interfaces.write_request import WriteRequest
from ....shared.patterns import fqid_from_collection_and_id
from ...util.typing import ActionData, ActionResultElement, ActionResults
from ..motion_change_recommendation.create import MotionChangeRecommendationCreateAction
from .create_base import MotionCreateBase


Expand Down Expand Up @@ -193,9 +194,31 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]:
self.set_origin_ids(instance)
self.set_text_hash(instance)
instance["forwarded"] = round(time.time())
with_change_recommendations = instance.pop("with_change_recommendations", False)
self.datastore.apply_changed_model(
fqid_from_collection_and_id("motion", instance["id"]), instance
)
if with_change_recommendations:
change_recos = self.datastore.filter(
"motion_change_recommendation",
FilterOperator("motion_id", "=", instance["origin_id"]),
[
"rejected",
"internal",
"type",
"other_description",
"line_from",
"line_to",
"text",
],
)
change_reco_data = [
{**change_reco, "motion_id": instance["id"]}
for change_reco in change_recos.values()
]
self.execute_other_action(
MotionChangeRecommendationCreateAction, change_reco_data
)
amendment_ids = self.datastore.get(
fqid_from_collection_and_id("motion", instance["origin_id"]),
["amendment_ids"],
Expand Down Expand Up @@ -254,6 +277,7 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]:
"meeting_id": instance["meeting_id"],
"use_original_submitter": use_original_submitter,
"use_original_number": use_original_number,
"with_change_recommendations": with_change_recommendations,
}
)
amendment.pop("meta_position", 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class MotionCreateForwarded(BaseMotionCreateForwarded):
additional_optional_fields={
"use_original_submitter": {"type": "boolean"},
"use_original_number": {"type": "boolean"},
"with_change_recommendations": {"type": "boolean"},
"with_amendments": {"type": "boolean"},
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class MotionCreateForwardedAmendment(BaseMotionCreateForwarded):
additional_optional_fields={
"use_original_submitter": {"type": "boolean"},
"use_original_number": {"type": "boolean"},
"with_change_recommendations": {"type": "boolean"},
},
)

Expand Down
222 changes: 222 additions & 0 deletions tests/system/action/motion/test_create_forwarded.py
Original file line number Diff line number Diff line change
Expand Up @@ -1316,3 +1316,225 @@ def test_name_generation(self) -> None:
"Sue B. Mid-Edit",
]:
assert name in motion["additional_submitter"]

def test_with_change_recommendations(self) -> None:
self.set_models(self.test_model)
self.set_models(
{
"motion/12": {"change_recommendation_ids": [1, 2]},
"meeting/1": {"motion_change_recommendation_ids": [1, 2]},
"motion_change_recommendation/1": {
"line_from": 11,
"line_to": 23,
"text": "Hello world",
"motion_id": 12,
"meeting_id": 1,
"rejected": True,
"internal": True,
"type": "replacement",
"other_description": "Iamachangerecommendation",
"creation_time": 0,
},
"motion_change_recommendation/2": {
"line_from": 24,
"line_to": 25,
"text": "!",
"motion_id": 12,
"meeting_id": 1,
"type": "replacement",
"creation_time": 1,
},
}
)
response = self.request(
"motion.create_forwarded",
{
"title": "test_Xcdfgee",
"meeting_id": 2,
"origin_id": 12,
"text": "test",
"reason": "reason_jLvcgAMx",
"with_change_recommendations": True,
},
)
self.assert_status_code(response, 200)
created_id = response.json["results"][0][0]["id"]
self.assert_model_exists(
f"motion/{created_id}", {"change_recommendation_ids": [3, 4]}
)
reco = self.assert_model_exists(
"motion_change_recommendation/3",
{
"line_from": 11,
"line_to": 23,
"text": "Hello world",
"motion_id": created_id,
"meeting_id": 2,
"rejected": True,
"internal": True,
"type": "replacement",
"other_description": "Iamachangerecommendation",
},
)
assert reco["creation_time"] > 0
reco = self.assert_model_exists(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reco isn't used after this line.

"motion_change_recommendation/4",
{
"line_from": 24,
"line_to": 25,
"text": "!",
"type": "replacement",
"motion_id": created_id,
"meeting_id": 2,
},
)

def test_without_change_recommendations(self) -> None:
self.set_models(self.test_model)
self.set_models(
{
"motion/12": {"change_recommendation_ids": [1, 2]},
"meeting/1": {"motion_change_recommendation_ids": [1, 2]},
"motion_change_recommendation/1": {
"line_from": 11,
"line_to": 23,
"text": "Hello world",
"motion_id": 12,
"meeting_id": 1,
"rejected": True,
"internal": True,
"type": "replacement",
"other_description": "Iamachangerecommendation",
"creation_time": 0,
},
"motion_change_recommendation/2": {
"line_from": 24,
"line_to": 25,
"text": "!",
"motion_id": 12,
"meeting_id": 1,
"type": "replacement",
"creation_time": 1,
},
}
)
response = self.request(
"motion.create_forwarded",
{
"title": "test_Xcdfgee",
"meeting_id": 2,
"origin_id": 12,
"text": "test",
"reason": "reason_jLvcgAMx",
},
)
self.assert_status_code(response, 200)
created_id = response.json["results"][0][0]["id"]
self.assert_model_exists(
f"motion/{created_id}", {"change_recommendation_ids": None}
)
self.assert_model_not_exists("motion_change_recommendation/3")

def test_with_no_change_recommendations(self) -> None:
self.set_models(self.test_model)
response = self.request(
"motion.create_forwarded",
{
"title": "test_Xcdfgee",
"meeting_id": 2,
"origin_id": 12,
"text": "test",
"reason": "reason_jLvcgAMx",
"with_change_recommendations": True,
},
)
self.assert_status_code(response, 200)

def test_with_amendment_change_recommendations(self) -> None:
self.set_models(self.test_model)
self.set_models(
{
"motion/12": {"change_recommendation_ids": [1], "amendment_ids": [13]},
"meeting/1": {"motion_change_recommendation_ids": [1, 2]},
"motion/13": {
"number": "AMNDMNT1",
"title": "amendment1",
"meeting_id": 1,
"derived_motion_ids": [],
"all_origin_ids": [],
"all_derived_motion_ids": [],
"lead_motion_id": 12,
"state_id": 30,
"text": "bla",
"change_recommendation_ids": [2],
},
"motion_change_recommendation/1": {
"line_from": 11,
"line_to": 23,
"text": "Hello world",
"motion_id": 12,
"meeting_id": 1,
"rejected": True,
"internal": True,
"type": "replacement",
"other_description": "Iamachangerecommendation",
"creation_time": 0,
},
"motion_change_recommendation/2": {
"line_from": 24,
"line_to": 25,
"text": "!",
"motion_id": 13,
"meeting_id": 1,
"type": "replacement",
"creation_time": 1,
},
}
)
response = self.request(
"motion.create_forwarded",
{
"title": "test_Xcdfgee",
"meeting_id": 2,
"origin_id": 12,
"text": "test",
"reason": "reason_jLvcgAMx",
"with_change_recommendations": True,
"with_amendments": True,
},
)
self.assert_status_code(response, 200)
created_id = response.json["results"][0][0]["id"]
self.assert_model_exists(
f"motion/{created_id}", {"change_recommendation_ids": [3]}
)
self.assert_model_exists(
f"motion/{created_id+1}",
{"change_recommendation_ids": [4], "lead_motion_id": created_id},
)
reco = self.assert_model_exists(
"motion_change_recommendation/3",
{
"line_from": 11,
"line_to": 23,
"text": "Hello world",
"motion_id": created_id,
"meeting_id": 2,
"rejected": True,
"internal": True,
"type": "replacement",
"other_description": "Iamachangerecommendation",
},
)
assert reco["creation_time"] > 0
reco = self.assert_model_exists(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reco isn't used after this line.

"motion_change_recommendation/4",
{
"line_from": 24,
"line_to": 25,
"text": "!",
"type": "replacement",
"motion_id": created_id + 1,
"meeting_id": 2,
},
)