diff --git a/docs/actions/list_of_speakers.re_add_last.md b/docs/actions/list_of_speakers.re_add_last.md index 872b6525b..264cafb7e 100644 --- a/docs/actions/list_of_speakers.re_add_last.md +++ b/docs/actions/list_of_speakers.re_add_last.md @@ -7,6 +7,7 @@ Readds the last finished speaker user (the highest `end_time`) to the list of waiting speakers. This fails, if - There is no last finished speaker - The last finished speaker is already a waiting speaker with the same point-of-order status +- The speech state of the last speaker is `interposed_question` and there is no unfinished speaker The new waiting speaker gets the weight of `min-1` of all waiting speakers or 1, if there are no waiting speakers. diff --git a/openslides_backend/action/actions/list_of_speakers/re_add_last.py b/openslides_backend/action/actions/list_of_speakers/re_add_last.py index 89bebccfe..ee83d7d86 100644 --- a/openslides_backend/action/actions/list_of_speakers/re_add_last.py +++ b/openslides_backend/action/actions/list_of_speakers/re_add_last.py @@ -40,6 +40,7 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]: mapped_fields=[ "id", "end_time", + "begin_time", "meeting_user_id", "weight", "point_of_order", @@ -53,6 +54,7 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]: # Get last speaker. last_speaker, lowest_weight = None, None + has_current_speaker = False for speaker in speakers.values(): speaker_weight = speaker.get("weight") or 0 if lowest_weight is None or speaker_weight < lowest_weight: @@ -63,9 +65,18 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]: last_speaker ): last_speaker = speaker + elif speaker.get("begin_time") is not None: + has_current_speaker = True if last_speaker is None: raise ActionException("There is no last speaker that can be re-added.") assert isinstance(lowest_weight, int) + if ( + last_speaker.get("speech_state") == "interposed_question" + and not has_current_speaker + ): + raise ActionException( + "Can't re-add interposed question when there's no current speaker" + ) meeting = self.datastore.get( fqid_from_collection_and_id("meeting", meeting_id), diff --git a/tests/system/action/list_of_speakers/test_re_add_last.py b/tests/system/action/list_of_speakers/test_re_add_last.py index fec349cf4..94e2229d8 100644 --- a/tests/system/action/list_of_speakers/test_re_add_last.py +++ b/tests/system/action/list_of_speakers/test_re_add_last.py @@ -178,6 +178,89 @@ def test_last_speaker_also_in_waiting_list_allowed(self) -> None: response = self.request("list_of_speakers.re_add_last", {"id": 111}) self.assert_status_code(response, 200) + def test_with_interposed_question(self) -> None: + self.set_models( + { + "meeting/1": { + "list_of_speakers_enable_interposed_question": True, + }, + "list_of_speakers/222": { + "meeting_id": 1, + "speaker_ids": [333, 334, 335], + }, + "speaker/333": { + "list_of_speakers_id": 222, + "meeting_user_id": 42, + "begin_time": 1000, + "total_pause": 1000, + "meeting_id": 1, + "weight": 1, + }, + "speaker/334": { + "list_of_speakers_id": 222, + "meeting_user_id": 43, + "meeting_id": 1, + "weight": 2, + }, + "speaker/335": { + "list_of_speakers_id": 222, + "meeting_user_id": 44, + "meeting_id": 1, + "weight": 1, + "begin_time": 1500, + "end_time": 2500, + "speech_state": "interposed_question", + }, + } + ) + response = self.request("list_of_speakers.re_add_last", {"id": 222}) + self.assert_status_code(response, 200) + self.assert_model_exists("speaker/333", {"weight": 1}) + self.assert_model_exists("speaker/334", {"weight": 2}) + self.assert_model_exists("speaker/335", {"weight": 0}) + + def test_with_interposed_question_error(self) -> None: + self.set_models( + { + "meeting/1": { + "list_of_speakers_enable_interposed_question": True, + }, + "list_of_speakers/222": { + "meeting_id": 1, + "speaker_ids": [333, 334, 335], + }, + "speaker/333": { + "list_of_speakers_id": 222, + "meeting_user_id": 42, + "begin_time": 1000, + "end_time": 1500, + "meeting_id": 1, + "weight": 1, + }, + "speaker/334": { + "list_of_speakers_id": 222, + "meeting_user_id": 43, + "meeting_id": 1, + "weight": 2, + }, + "speaker/335": { + "list_of_speakers_id": 222, + "meeting_user_id": 44, + "meeting_id": 1, + "weight": 1, + "begin_time": 1500, + "end_time": 2500, + "speech_state": "interposed_question", + }, + } + ) + response = self.request("list_of_speakers.re_add_last", {"id": 222}) + self.assert_status_code(response, 400) + assert ( + "Can't re-add interposed question when there's no current speaker" + in response.json["message"] + ) + def test_last_speaker_also_in_waiting_list_but_poos(self) -> None: self.set_models( { @@ -252,6 +335,8 @@ def test_tie_breakers(self) -> None: "end_time": None, }, ) + if i == 222: + self.request("speaker.speak", {"id": 222}) def test_re_add_last_no_permissions(self) -> None: self.base_permission_test(