Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 14 additions & 7 deletions data/example-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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": {
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions docs/Actions-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion docs/actions/meeting_user.update.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

// Optional
poll_option_ids: Id[];
poll_voted_ids: Id[];
acting_ballot_ids: Id[];
represented_ballot_ids: Id[];

Expand Down
9 changes: 9 additions & 0 deletions docs/actions/poll_ballot_user.delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Payload

```js
{ id: Id; }
```

## Internal action

Deletes a poll_ballot_user.
10 changes: 8 additions & 2 deletions openslides_backend/action/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions openslides_backend/action/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 2 additions & 3 deletions openslides_backend/action/actions/meeting_user/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class MeetingUserUpdate(
"motion_supporter_ids",
"motion_submitter_ids",
"chat_message_ids",
"acting_ballot_ids",
"represented_ballot_ids",
]

model = MeetingUser()
Expand All @@ -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,
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import delete # noqa
15 changes: 15 additions & 0 deletions openslides_backend/action/actions/poll_ballot_user/delete.py
Original file line number Diff line number Diff line change
@@ -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()
10 changes: 2 additions & 8 deletions openslides_backend/action/actions/user/merge_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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", []))
+ (
Expand All @@ -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:
Expand All @@ -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()})
Expand Down
3 changes: 0 additions & 3 deletions openslides_backend/action/generics/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions openslides_backend/models/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
47 changes: 24 additions & 23 deletions openslides_backend/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"},
Expand Down Expand Up @@ -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
)


Expand Down
2 changes: 1 addition & 1 deletion openslides_backend/shared/export_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
9 changes: 9 additions & 0 deletions tests/system/action/meeting/test_clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(
Expand Down
1 change: 1 addition & 0 deletions tests/system/action/meeting/test_delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading
Loading