diff --git a/data/example-data.json b/data/example-data.json index 6b037ed50e..663fec2c0b 100644 --- a/data/example-data.json +++ b/data/example-data.json @@ -157,10 +157,9 @@ "assignment_candidate_ids": [1], "structure_level_ids": [1], "group_ids": [2], - "poll_voted_ids": [3], "poll_option_ids": [1, 8], - "acting_ballot_ids": [9], - "represented_ballot_ids": [9] + "acting_ballot_ids": [1], + "represented_ballot_ids": [1] }, "2": { "id": 2, @@ -1952,7 +1951,7 @@ "allow_vote_split": false, "content_object_id": "motion/1", "ballot_ids": [9], - "voted_ids": [1], + "ballot_user_ids": [1], "meeting_id": 1 }, "4": { @@ -2178,12 +2177,20 @@ "id": 9, "value": "1", "weight": "1.000000", + "split": false, + "poll_id": 3, + "poll_ballot_user_id": 1 + } + }, + "poll_ballot_user": { + "1": { + "id": 1, "acting_meeting_user_id": 1, "represented_meeting_user_id": 1, - "split": false, - "poll_id": 3 + "poll_id": 3, + "poll_ballot_id": 9 } - }, + }, "assignment": { "1": { "id": 1, diff --git a/docs/Actions-Overview.md b/docs/Actions-Overview.md index 09e272afa2..f37c9221cd 100644 --- a/docs/Actions-Overview.md +++ b/docs/Actions-Overview.md @@ -182,6 +182,7 @@ A more general format description see in [Action-Service](https://github.com/Ope - [poll.delete](actions/poll.delete.md) - [poll_ballot.delete](actions/poll_ballot.delete.md) +- [poll_ballot_user.delete](actions/poll_ballot_user.delete.md) - [poll_config_approval.delete](actions/poll_config_approval.delete.md) - [poll_config_rating_approval.delete](actions/poll_config_rating_approval.delete.md) - [poll_config_rating_score.delete](actions/poll_config_rating_score.delete.md) diff --git a/docs/actions/meeting_user.update.md b/docs/actions/meeting_user.update.md index aeb77b500d..d632eac4fe 100644 --- a/docs/actions/meeting_user.update.md +++ b/docs/actions/meeting_user.update.md @@ -6,7 +6,6 @@ // Optional poll_option_ids: Id[]; - poll_voted_ids: Id[]; acting_ballot_ids: Id[]; represented_ballot_ids: Id[]; diff --git a/docs/actions/poll_ballot_user.delete.md b/docs/actions/poll_ballot_user.delete.md new file mode 100644 index 0000000000..f73c6b9778 --- /dev/null +++ b/docs/actions/poll_ballot_user.delete.md @@ -0,0 +1,9 @@ +## Payload + +```js +{ id: Id; } +``` + +## Internal action + +Deletes a poll_ballot_user. diff --git a/meta b/meta index c6e391473e..6d54f6540a 160000 --- a/meta +++ b/meta @@ -1 +1 @@ -Subproject commit c6e391473ea75459b61c527731776c6f5fd2937a +Subproject commit 6d54f6540a661842e1af030ca0199aa6c0b4adad diff --git a/openslides_backend/action/action.py b/openslides_backend/action/action.py index 53f9de661e..fca7057fba 100644 --- a/openslides_backend/action/action.py +++ b/openslides_backend/action/action.py @@ -436,8 +436,11 @@ def _build_write_request( # sort events: create - update - delete events_by_type: dict[EventType, list[Event]] = defaultdict(list) for event in self.events: - self.apply_event(event) - events_by_type[event["type"]].append(event) + if event["type"] == "delete" or not self.is_to_be_deleted( + event["fqid"] + ): + self.apply_event(event) + events_by_type[event["type"]].append(event) information = self.get_full_history_information() if self.is_sub_call: write_request.information = information @@ -765,6 +768,9 @@ def get_post_edit_function(self) -> EditFunction | None: """ return None + def is_to_be_deleted(self, fqid: FullQualifiedId) -> bool: + return self.datastore.is_to_be_deleted(fqid) + def merge_history_informations( a: HistoryInformation | None, *other: HistoryInformation | None diff --git a/openslides_backend/action/actions/__init__.py b/openslides_backend/action/actions/__init__.py index cc8ecbe8ed..0604765ddf 100644 --- a/openslides_backend/action/actions/__init__.py +++ b/openslides_backend/action/actions/__init__.py @@ -40,6 +40,7 @@ def prepare_actions_map() -> None: point_of_order_category, poll, poll_ballot, + poll_ballot_user, poll_config_approval, poll_config_rating_approval, poll_config_rating_score, diff --git a/openslides_backend/action/actions/meeting_user/update.py b/openslides_backend/action/actions/meeting_user/update.py index a3ef6a3438..deb59b733b 100644 --- a/openslides_backend/action/actions/meeting_user/update.py +++ b/openslides_backend/action/actions/meeting_user/update.py @@ -34,6 +34,8 @@ class MeetingUserUpdate( "motion_supporter_ids", "motion_submitter_ids", "chat_message_ids", + "acting_ballot_ids", + "represented_ballot_ids", ] model = MeetingUser() @@ -42,9 +44,6 @@ class MeetingUserUpdate( "about_me", "group_ids", "poll_option_ids", - "poll_voted_ids", - "acting_ballot_ids", - "represented_ballot_ids", *meeting_user_standard_fields, *merge_fields, ], diff --git a/openslides_backend/action/actions/poll_ballot_user/__init__.py b/openslides_backend/action/actions/poll_ballot_user/__init__.py new file mode 100644 index 0000000000..1fc925d0d8 --- /dev/null +++ b/openslides_backend/action/actions/poll_ballot_user/__init__.py @@ -0,0 +1 @@ +from . import delete # noqa diff --git a/openslides_backend/action/actions/poll_ballot_user/delete.py b/openslides_backend/action/actions/poll_ballot_user/delete.py new file mode 100644 index 0000000000..ca70e6158f --- /dev/null +++ b/openslides_backend/action/actions/poll_ballot_user/delete.py @@ -0,0 +1,15 @@ +from ....models.models import PollBallotUser +from ...generics.delete import DeleteAction +from ...util.action_type import ActionType +from ...util.default_schema import DefaultSchema +from ...util.register import register_action + + +@register_action("poll_ballot_user.delete", action_type=ActionType.BACKEND_INTERNAL) +class PollBallotUserDelete(DeleteAction): + """ + Action to delete a poll_ballot_user. + """ + + model = PollBallotUser() + schema = DefaultSchema(PollBallotUser()).get_delete_schema() diff --git a/openslides_backend/action/actions/user/merge_mixins.py b/openslides_backend/action/actions/user/merge_mixins.py index 5b5f7bea20..15429f7bf3 100644 --- a/openslides_backend/action/actions/user/merge_mixins.py +++ b/openslides_backend/action/actions/user/merge_mixins.py @@ -230,7 +230,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "group_ids", "structure_level_ids", "history_entry_ids", - "poll_voted_ids", # throw error if conflict on same poll "poll_option_ids", # throw error if conflict on same poll "acting_ballot_ids", # throw error if conflict on same poll "represented_ballot_ids", # throw error if conflict on same poll @@ -306,7 +305,6 @@ def check_polls(self, into: PartialModel, other_models: list[PartialModel]) -> N "group_ids", "vote_delegations_from_ids", "vote_delegated_to_id", - "poll_voted_ids", "poll_option_ids", "acting_ballot_ids", "represented_ballot_ids", @@ -395,10 +393,6 @@ def check_polls(self, into: PartialModel, other_models: list[PartialModel]) -> N ballot_poll_ids_per_user_id: dict[int, set[int]] = {} option_poll_ids_per_user_id: dict[int, set[int]] = {} for meeting_user in meeting_users.values(): - if poll_voted_ids := meeting_user.get("poll_voted_ids"): - ballot_poll_ids_per_user_id.setdefault( - meeting_user["user_id"], set() - ).update(set(poll_voted_ids)) if len( (o_ids := meeting_user.get("poll_option_ids", [])) + ( @@ -416,7 +410,7 @@ def check_polls(self, into: PartialModel, other_models: list[PartialModel]) -> N many_models = self.datastore.get_many( [ GetManyRequest("poll_option", o_ids, ["poll_id"]), - GetManyRequest("poll_ballot", b_ids, ["poll_id"]), + GetManyRequest("poll_ballot_user", b_ids, ["poll_id"]), ] ) if o_ids: @@ -428,7 +422,7 @@ def check_polls(self, into: PartialModel, other_models: list[PartialModel]) -> N for option in many_models["poll_option"].values() } ) - ballot_data = many_models["poll_ballot"] + ballot_data = many_models["poll_ballot_user"] ballot_poll_ids_per_user_id.setdefault( meeting_user["user_id"], set() ).update({ballot["poll_id"] for ballot in ballot_data.values()}) diff --git a/openslides_backend/action/generics/delete.py b/openslides_backend/action/generics/delete.py index b5a39361de..f8d4c6624c 100644 --- a/openslides_backend/action/generics/delete.py +++ b/openslides_backend/action/generics/delete.py @@ -116,6 +116,3 @@ def is_meeting_to_be_deleted(self, meeting_id: int) -> bool: return self.datastore.is_to_be_deleted( fqid_from_collection_and_id("meeting", meeting_id) ) - - def is_to_be_deleted(self, fqid: FullQualifiedId) -> bool: - return self.datastore.is_to_be_deleted(fqid) diff --git a/openslides_backend/models/checker.py b/openslides_backend/models/checker.py index ecc1709225..9774905bf4 100644 --- a/openslides_backend/models/checker.py +++ b/openslides_backend/models/checker.py @@ -193,6 +193,7 @@ def check_timestamp(value: Any) -> bool: "user", "mediafile", "poll_ballot", + "poll_ballot_user", "poll_config_approval", "poll_config_selection", "poll_config_rating_score", diff --git a/openslides_backend/models/models.py b/openslides_backend/models/models.py index bf17bf33df..a516c0f113 100644 --- a/openslides_backend/models/models.py +++ b/openslides_backend/models/models.py @@ -1518,25 +1518,14 @@ class MeetingUser(Model): vote_delegations_from_ids = fields.RelationListField( to={"meeting_user": "vote_delegated_to_id"}, is_view_field=True ) - poll_voted_ids = fields.RelationListField( - to={"poll": "voted_ids"}, - is_view_field=True, - is_primary=True, - write_fields=( - "nm_meeting_user_poll_voted_ids_poll_t", - "meeting_user_id", - "poll_id", - [], - ), - ) poll_option_ids = fields.RelationListField( to={"poll_option": "meeting_user_id"}, is_view_field=True, is_primary=True ) acting_ballot_ids = fields.RelationListField( - to={"poll_ballot": "acting_meeting_user_id"}, is_view_field=True + to={"poll_ballot_user": "acting_meeting_user_id"}, is_view_field=True ) represented_ballot_ids = fields.RelationListField( - to={"poll_ballot": "represented_meeting_user_id"}, is_view_field=True + to={"poll_ballot_user": "represented_meeting_user_id"}, is_view_field=True ) chat_message_ids = fields.RelationListField( to={"chat_message": "meeting_user_id"}, is_view_field=True @@ -2346,15 +2335,11 @@ class Poll(Model, PollModelMixin): is_view_field=True, is_primary=True, ) - voted_ids = fields.RelationListField( - to={"meeting_user": "poll_voted_ids"}, + ballot_user_ids = fields.RelationListField( + to={"poll_ballot_user": "poll_id"}, + on_delete=fields.OnDelete.CASCADE, is_view_field=True, - write_fields=( - "nm_meeting_user_poll_voted_ids_poll_t", - "poll_id", - "meeting_user_id", - [], - ), + is_primary=True, ) entitled_group_ids = fields.RelationListField( to={"group": "poll_ids"}, @@ -2385,11 +2370,27 @@ class PollBallot(Model): poll_id = fields.RelationField( to={"poll": "ballot_ids"}, required=True, constant=True ) + poll_ballot_user_id = fields.RelationField( + to={"poll_ballot_user": "poll_ballot_id"} + ) + + +class PollBallotUser(Model): + collection = "poll_ballot_user" + verbose_name = "poll ballot user" + + id = fields.IntegerField(required=True, constant=True) + poll_id = fields.RelationField( + to={"poll": "ballot_user_ids"}, required=True, constant=True + ) + poll_ballot_id = fields.RelationField( + to={"poll_ballot": "poll_ballot_user_id"}, is_view_field=True + ) acting_meeting_user_id = fields.RelationField( - to={"meeting_user": "acting_ballot_ids"} + to={"meeting_user": "acting_ballot_ids"}, required=True ) represented_meeting_user_id = fields.RelationField( - to={"meeting_user": "represented_ballot_ids"} + to={"meeting_user": "represented_ballot_ids"}, required=True ) diff --git a/openslides_backend/shared/export_helper.py b/openslides_backend/shared/export_helper.py index d24f97f2a7..5484a2b9f8 100644 --- a/openslides_backend/shared/export_helper.py +++ b/openslides_backend/shared/export_helper.py @@ -212,7 +212,7 @@ def export_meeting( if polls := export.get("poll"): related_collections: dict[str, list[int]] = {} for poll in polls.values(): - for collection_base_name in ["ballot", "option"]: + for collection_base_name in ["ballot", "ballot_user", "option"]: if ids := poll.get(f"{collection_base_name}_ids"): related_collections.setdefault( f"poll_{collection_base_name}", list() diff --git a/tests/system/action/meeting/test_clone.py b/tests/system/action/meeting/test_clone.py index b924f43647..9adb1061c0 100644 --- a/tests/system/action/meeting/test_clone.py +++ b/tests/system/action/meeting/test_clone.py @@ -1979,6 +1979,10 @@ def test_clone_vote_delegated_vote(self) -> None: "onehundred_percent_base": Poll.ONEHUNDRED_PERCENT_BASE_VALID }, f"poll_ballot/{poll_id}": { + "poll_id": poll_id, + "poll_ballot_user_id": poll_id, + }, + f"poll_ballot_user/{poll_id}": { "acting_meeting_user_id": 1 if poll_id == 1 else 2, "represented_meeting_user_id": 1 if poll_id == 1 else 2, "poll_id": poll_id, @@ -1989,10 +1993,15 @@ def test_clone_vote_delegated_vote(self) -> None: self.assert_status_code(response, 200) self.assert_model_exists( "poll_ballot/5", + {"poll_id": 5, "poll_ballot_user_id": 5}, + ) + self.assert_model_exists( + "poll_ballot_user/5", { "acting_meeting_user_id": 3, "represented_meeting_user_id": 3, "poll_id": 5, + "poll_ballot_id": 5, }, ) self.assert_model_exists( diff --git a/tests/system/action/meeting/test_delete.py b/tests/system/action/meeting/test_delete.py index d0a7795f16..6da7356058 100644 --- a/tests/system/action/meeting/test_delete.py +++ b/tests/system/action/meeting/test_delete.py @@ -445,6 +445,7 @@ def test_delete_full_meeting(self) -> None: self.assert_model_not_exists(f"poll_option/{i+1}") for i in range(9): self.assert_model_not_exists(f"poll_ballot/{i+1}") + self.assert_model_not_exists("poll_ballot_user/1") for i in range(2): self.assert_model_not_exists(f"poll_config_approval/{i+1}") self.assert_model_not_exists("poll_config_selection/1") diff --git a/tests/system/action/meeting/test_import.py b/tests/system/action/meeting/test_import.py index 3d8d15efdb..7a280e9b84 100644 --- a/tests/system/action/meeting/test_import.py +++ b/tests/system/action/meeting/test_import.py @@ -2397,9 +2397,13 @@ def prepare_user_with_ballot_data(self) -> dict[str, dict[str, Any]]: { **self.get_assignment_poll_data(3), "poll_ballot": { - "7": { - "id": 7, + "7": {"id": 7, "poll_id": 3, "poll_ballot_user_id": 14}, + }, + "poll_ballot_user": { + "14": { + "id": 14, "poll_id": 3, + "poll_ballot_id": 7, "acting_meeting_user_id": 11, "represented_meeting_user_id": 11, }, @@ -2418,9 +2422,8 @@ def prepare_user_with_ballot_data(self) -> dict[str, dict[str, Any]]: }, "meeting_user": { "11": { - "poll_voted_ids": [3], - "acting_ballot_ids": [7], - "represented_ballot_ids": [7], + "acting_ballot_ids": [14], + "represented_ballot_ids": [14], } }, } @@ -2429,7 +2432,7 @@ def prepare_user_with_ballot_data(self) -> dict[str, dict[str, Any]]: { "entitled_group_ids": [2], "ballot_ids": [7], - "voted_ids": [11], + "ballot_user_ids": [14], } ) return data @@ -2451,11 +2454,14 @@ def test_import_new_user_with_ballot(self) -> None: "onehundred_percent_base": Poll.ONEHUNDRED_PERCENT_BASE_VALID, }, "poll_ballot/1": { + "poll_id": 1, + "poll_ballot_user_id": 1, + }, + "poll_ballot_user/1": { "acting_meeting_user_id": 1, "represented_meeting_user_id": 1, "poll_id": 1, }, - "meeting_user/1": {"poll_voted_ids": [1]}, } ) @@ -2483,7 +2489,6 @@ def test_import_new_user_with_ballot(self) -> None: "meeting_id": 1, "acting_ballot_ids": [1], "represented_ballot_ids": [1], - "poll_voted_ids": [1], }, ) self.assert_model_exists( @@ -2493,7 +2498,6 @@ def test_import_new_user_with_ballot(self) -> None: "meeting_id": 2, "acting_ballot_ids": [2], "represented_ballot_ids": [2], - "poll_voted_ids": [2], }, ) self.assert_model_exists( @@ -2503,7 +2507,6 @@ def test_import_new_user_with_ballot(self) -> None: "meeting_id": 2, "acting_ballot_ids": None, "represented_ballot_ids": None, - "poll_voted_ids": None, }, ) self.assert_model_exists( @@ -2513,7 +2516,7 @@ def test_import_new_user_with_ballot(self) -> None: "content_object_id": "assignment/1", "meeting_id": 2, "ballot_ids": [2], - "voted_ids": [2], + "ballot_user_ids": [2], "entitled_group_ids": [5], }, ) diff --git a/tests/system/action/meeting_user/test_update.py b/tests/system/action/meeting_user/test_update.py index 91d6d31adc..d292e9622d 100644 --- a/tests/system/action/meeting_user/test_update.py +++ b/tests/system/action/meeting_user/test_update.py @@ -150,11 +150,19 @@ def test_update_with_poll_related_fields(self) -> None: "onehundred_percent_base": Poll.ONEHUNDRED_PERCENT_BASE_VALID }, "poll_ballot/1": { + "poll_id": 1, + "poll_ballot_user_id": 1, + }, + "poll_ballot_user/1": { "poll_id": 1, "acting_meeting_user_id": 1, "represented_meeting_user_id": 1, }, "poll_ballot/2": { + "poll_id": 1, + "poll_ballot_user_id": 2, + }, + "poll_ballot_user/2": { "poll_id": 1, "acting_meeting_user_id": 1, "represented_meeting_user_id": 2, @@ -166,7 +174,6 @@ def test_update_with_poll_related_fields(self) -> None: { "id": 3, "poll_option_ids": [1], - "poll_voted_ids": [1], "acting_ballot_ids": [1], "represented_ballot_ids": [2], }, @@ -176,14 +183,22 @@ def test_update_with_poll_related_fields(self) -> None: expected: dict[str, dict[str, Any]] = { "meeting_user/3": { "poll_option_ids": [1], - "poll_voted_ids": [1], "acting_ballot_ids": [1], "represented_ballot_ids": [2], }, - "poll/1": {"voted_ids": [3]}, + "poll/1": {"ballot_user_ids": [1, 2]}, "poll_option/1": {"meeting_user_id": 3}, - "poll_ballot/1": {"acting_meeting_user_id": 3}, - "poll_ballot/2": {"represented_meeting_user_id": 3}, + "poll_ballot_user/1": { + "poll_id": 1, + "acting_meeting_user_id": 3, + "represented_meeting_user_id": 1, + }, + "poll_ballot_user/2": { + "poll_id": 1, + "poll_ballot_id": 2, + "acting_meeting_user_id": 1, + "represented_meeting_user_id": 3, + }, } for fqid, model in expected.items(): self.assert_model_exists(fqid, model) diff --git a/tests/system/action/user/test_merge_together.py b/tests/system/action/user/test_merge_together.py index 8e1e269564..b3e24fb064 100644 --- a/tests/system/action/user/test_merge_together.py +++ b/tests/system/action/user/test_merge_together.py @@ -1084,37 +1084,66 @@ def create_polls_with_correct_votes(self) -> None: self.set_up_polls_for_merge() self.set_models( { - "meeting_user/12": {"poll_voted_ids": [2]}, - "meeting_user/14": {"poll_voted_ids": [1]}, - "meeting_user/15": {"poll_voted_ids": [1]}, - "meeting_user/43": {"poll_voted_ids": [5]}, - "meeting_user/73": {"poll_voted_ids": [6]}, - "poll_ballot/1": { + "poll_ballot/11": { "value": "no", + "poll_id": 1, + "poll_ballot_user_id": 1, + }, + "poll_ballot_user/1": { "poll_id": 1, "acting_meeting_user_id": 14, "represented_meeting_user_id": 14, }, - "poll_ballot/2": { + "poll_ballot/12": { "value": "no", + "poll_id": 1, + "poll_ballot_user_id": 2, + }, + "poll_ballot_user/2": { "poll_id": 1, "acting_meeting_user_id": 14, "represented_meeting_user_id": 15, }, - "poll_ballot/3": { + "poll_ballot/13": { "value": "4", + "poll_id": 2, + "poll_ballot_user_id": 3, + }, + "poll_ballot_user/3": { "poll_id": 2, "acting_meeting_user_id": 12, "represented_meeting_user_id": 12, }, - "poll_ballot/4": { + "poll_ballot/14": { "value": "abstain", + "poll_id": 5, + "poll_ballot_user_id": 4, + }, + "poll_ballot_user/4": { "poll_id": 5, "acting_meeting_user_id": 43, "represented_meeting_user_id": 43, }, - "poll_ballot/5": {"value": "9", "poll_id": 6}, - "poll_ballot/6": {"value": "10", "poll_id": 6}, + "group/7": { + "meeting_user_ids": [75], + }, + "meeting_user/75": { + "user_id": 5, + "meeting_id": 7, + "vote_weight": Decimal("1"), + }, + "poll_ballot/15": {"value": "9", "poll_id": 6}, + "poll_ballot_user/5": { + "poll_id": 6, + "acting_meeting_user_id": 75, + "represented_meeting_user_id": 75, + }, + "poll_ballot/16": {"value": "10", "poll_id": 6}, + "poll_ballot_user/6": { + "poll_id": 6, + "acting_meeting_user_id": 73, + "represented_meeting_user_id": 73, + }, } ) @@ -1135,7 +1164,7 @@ def assert_merge_with_polls_correct( }, ) self.assert_model_exists("committee/60", {"user_ids": [2, 5]}) - self.assert_model_exists("committee/66", {"user_ids": [2]}) + self.assert_model_exists("committee/66", {"user_ids": [2, 5]}) for id_ in range(3, 5): self.assert_model_not_exists(f"user/{id_}") for id_ in [43, 73, 14, 44, 74, *range(106, 106 + add_to_creatable_ids)]: @@ -1146,7 +1175,6 @@ def assert_merge_with_polls_correct( "user_id": 2, "meeting_id": 1, "poll_option_ids": [1, 4, 5, 7], - "poll_voted_ids": [1, 2], "acting_ballot_ids": [1, 2, 3], "represented_ballot_ids": [1, 3], }, @@ -1157,14 +1185,13 @@ def assert_merge_with_polls_correct( "user_id": 2, "meeting_id": 4, "motion_submitter_ids": [1], - "poll_voted_ids": [5], "acting_ballot_ids": [4], "represented_ballot_ids": [4], }, ) self.assert_model_exists( f"meeting_user/{106 + add_to_creatable_ids}", - {"user_id": 2, "meeting_id": 7, "poll_voted_ids": [6]}, + {"user_id": 2, "meeting_id": 7}, ) self.assert_model_not_exists("motion_submitter/2") self.assert_model_exists( @@ -1177,34 +1204,67 @@ def assert_merge_with_polls_correct( ) self.assert_model_exists( - "poll_ballot/2", + "poll_ballot_user/2", {"acting_meeting_user_id": 12, "represented_meeting_user_id": 15}, ) for id_ in [1, 3]: self.assert_model_exists( - f"poll_ballot/{id_}", + f"poll_ballot_user/{id_}", {"acting_meeting_user_id": 12, "represented_meeting_user_id": 12}, ) self.assert_model_exists( - "poll_ballot/4", + "poll_ballot_user/4", {"acting_meeting_user_id": 42, "represented_meeting_user_id": 42}, ) for id_ in [5, 6]: # anonymous ballots self.assert_model_exists( - f"poll_ballot/{id_}", + f"poll_ballot/{10 + id_}", { + "poll_id": 6, "value": str(id_ + 4), - "acting_meeting_user_id": None, - "represented_meeting_user_id": None, + "poll_ballot_user_id": None, }, ) + self.assert_model_exists( + "poll_ballot_user/5", + { + "poll_id": 6, + "poll_ballot_id": None, + "acting_meeting_user_id": 75, + "represented_meeting_user_id": 75, + }, + ) + self.assert_model_exists( + "poll_ballot_user/6", + { + "poll_id": 6, + "poll_ballot_id": None, + "acting_meeting_user_id": 106 + add_to_creatable_ids, + "represented_meeting_user_id": 106 + add_to_creatable_ids, + }, + ) - self.assert_model_exists("poll/1", {"voted_ids": [12, 15]}) - self.assert_model_exists("poll/2", {"voted_ids": [12]}) + self.assert_model_exists( + "poll/1", + {"ballot_ids": [11, 12], "ballot_user_ids": [1, 2]}, + ) + self.assert_model_exists( + "poll/2", + {"ballot_ids": [13], "ballot_user_ids": [3]}, + ) for id_ in [3, 4]: - self.assert_model_exists(f"poll/{id_}", {"voted_ids": None}) - self.assert_model_exists("poll/5", {"voted_ids": [42]}) - self.assert_model_exists("poll/6", {"voted_ids": [106 + add_to_creatable_ids]}) + self.assert_model_exists( + f"poll/{id_}", + {"ballot_ids": None, "ballot_user_ids": None}, + ) + self.assert_model_exists( + "poll/5", + {"ballot_ids": [14], "ballot_user_ids": [4]}, + ) + self.assert_model_exists( + "poll/6", + {"ballot_ids": [15, 16], "ballot_user_ids": [5, 6]}, + ) def test_merge_with_polls_correct(self) -> None: password = self.assert_model_exists("user/2")["password"] @@ -1227,37 +1287,66 @@ def test_merge_with_polls_all_errors(self) -> None: self.set_models( { "poll/4": {"state": Poll.STATE_STARTED}, - "meeting_user/12": {"poll_voted_ids": [2]}, - "meeting_user/14": {"poll_voted_ids": [1]}, - "meeting_user/15": {"poll_voted_ids": [1]}, - "meeting_user/43": {"poll_voted_ids": [5]}, - "meeting_user/73": {"poll_voted_ids": [6]}, - "poll_ballot/1": { + "poll_ballot/11": { "value": "no", + "poll_id": 1, + "poll_ballot_user_id": 1, + }, + "poll_ballot_user/1": { "poll_id": 1, "acting_meeting_user_id": 14, "represented_meeting_user_id": 14, }, - "poll_ballot/2": { + "poll_ballot/12": { "value": "no", + "poll_id": 1, + "poll_ballot_user_id": 2, + }, + "poll_ballot_user/2": { "poll_id": 1, "acting_meeting_user_id": 14, "represented_meeting_user_id": 15, }, - "poll_ballot/3": { + "poll_ballot/13": { "value": "4", + "poll_id": 2, + "poll_ballot_user_id": 3, + }, + "poll_ballot_user/3": { "poll_id": 2, "acting_meeting_user_id": 12, "represented_meeting_user_id": 12, }, - "poll_ballot/4": { + "poll_ballot/14": { "value": "abstain", + "poll_id": 5, + "poll_ballot_user_id": 4, + }, + "poll_ballot_user/4": { "poll_id": 5, "acting_meeting_user_id": 43, "represented_meeting_user_id": 43, }, - "poll_ballot/5": {"value": "9", "poll_id": 6}, - "poll_ballot/6": {"value": "10", "poll_id": 6}, + "group/7": { + "meeting_user_ids": [75], + }, + "meeting_user/75": { + "user_id": 5, + "meeting_id": 7, + "vote_weight": Decimal("1"), + }, + "poll_ballot/15": {"value": "9", "poll_id": 6}, + "poll_ballot_user/5": { + "poll_id": 6, + "acting_meeting_user_id": 75, + "represented_meeting_user_id": 75, + }, + "poll_ballot/16": {"value": "10", "poll_id": 6}, + "poll_ballot_user/6": { + "poll_id": 6, + "acting_meeting_user_id": 73, + "represented_meeting_user_id": 73, + }, } ) response = self.request("user.merge_together", {"id": 2, "user_ids": [3, 4, 5]}) @@ -1269,7 +1358,7 @@ def test_merge_with_polls_all_errors(self) -> None: "some of the users are entitled to vote in currently running polls in meeting(s) 1", "some of the selected users have different delegations roles in meeting(s) 1", "some of the selected users are delegating votes to each other in meeting(s) 1", - "among the selected users multiple voted in poll(s) 1", + "among the selected users multiple voted in poll(s) 1, 6", "multiple of the selected users are among the options in poll(s) 1, 2, 3, 4", ] ) diff --git a/tests/system/presenter/test_check_database.py b/tests/system/presenter/test_check_database.py index b4396de66e..b710571ae6 100644 --- a/tests/system/presenter/test_check_database.py +++ b/tests/system/presenter/test_check_database.py @@ -533,6 +533,10 @@ def test_correct_relations(self) -> None: "onehundred_percent_base": Poll.ONEHUNDRED_PERCENT_BASE_VALID }, "poll_ballot/8": { + "poll_id": 7, + "poll_ballot_user_id": 12, + }, + "poll_ballot_user/12": { "poll_id": 7, "acting_meeting_user_id": 14, "represented_meeting_user_id": 15, diff --git a/tests/system/presenter/test_check_database_all.py b/tests/system/presenter/test_check_database_all.py index d62a8a4af7..b6d7fe884e 100644 --- a/tests/system/presenter/test_check_database_all.py +++ b/tests/system/presenter/test_check_database_all.py @@ -609,6 +609,10 @@ def test_correct_relations(self) -> None: "onehundred_percent_base": Poll.ONEHUNDRED_PERCENT_BASE_VALID }, "poll_ballot/8": { + "poll_id": 7, + "poll_ballot_user_id": 12, + }, + "poll_ballot_user/12": { "poll_id": 7, "acting_meeting_user_id": 14, "represented_meeting_user_id": 15, diff --git a/tests/system/presenter/test_export_meeting.py b/tests/system/presenter/test_export_meeting.py index b7ff6c871d..317f47418e 100644 --- a/tests/system/presenter/test_export_meeting.py +++ b/tests/system/presenter/test_export_meeting.py @@ -246,7 +246,6 @@ def test_export_meeting_find_special_users(self) -> None: "meeting_user/114": { "meeting_id": 1, "user_id": 14, - "poll_voted_ids": [80], }, "poll/80": { "title": "Poll 80", @@ -263,6 +262,10 @@ def test_export_meeting_find_special_users(self) -> None: "poll_ballot/120": { "poll_id": 80, "value": "yes", + "poll_ballot_user_id": 130, + }, + "poll_ballot_user/130": { + "poll_id": 80, "represented_meeting_user_id": 114, "acting_meeting_user_id": 114, }, @@ -282,12 +285,12 @@ def test_export_meeting_find_special_users(self) -> None: assert data["poll_option"]["100"]["meeting_user_id"] == 113 assert data["meeting_user"]["113"]["poll_option_ids"] == [100] - assert data["poll"]["80"]["voted_ids"] == [114] - assert data["meeting_user"]["114"]["poll_voted_ids"] == [80] - assert data["poll_ballot"]["120"]["acting_meeting_user_id"] == 114 - assert data["poll_ballot"]["120"]["represented_meeting_user_id"] == 114 - assert data["meeting_user"]["114"]["acting_ballot_ids"] == [120] - assert data["meeting_user"]["114"]["represented_ballot_ids"] == [120] + assert data["poll"]["80"]["ballot_ids"] == [120] + assert data["poll"]["80"]["ballot_user_ids"] == [130] + assert data["poll_ballot_user"]["130"]["acting_meeting_user_id"] == 114 + assert data["poll_ballot_user"]["130"]["represented_meeting_user_id"] == 114 + assert data["meeting_user"]["114"]["acting_ballot_ids"] == [130] + assert data["meeting_user"]["114"]["represented_ballot_ids"] == [130] def create_assignment(self, meeting_id: int, base: int) -> None: self.set_models(