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
2 changes: 1 addition & 1 deletion meta
12 changes: 8 additions & 4 deletions openslides_backend/action/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from psycopg.types.json import Jsonb

from openslides_backend.shared.base_service_provider import BaseServiceProvider
from openslides_backend.shared.history_events import update_history_information_multi

from ..models.base import Model, model_registry
from ..models.fields import BaseRelationField, GenericRelationField
Expand Down Expand Up @@ -540,7 +541,7 @@ def get_history_information(self) -> HistoryInformation | None:
if self.history_information is None:
return None

information = {}
information: HistoryInformation = {}
instances = (
self.get_instances_with_fields(["id", self.history_relation_field])
if self.history_relation_field
Expand All @@ -558,8 +559,9 @@ def get_history_information(self) -> HistoryInformation | None:
fqids.append(
fqid_from_collection_and_id(self.model.collection, instance["id"])
)
for fqid in fqids:
information[fqid] = [self.history_information]
update_history_information_multi(
information, fqids, [self.history_information]
)
return information

def get_instances_with_fields(
Expand Down Expand Up @@ -777,7 +779,9 @@ def merge_history_informations(
b = {}
for fqid, information in b.items():
if fqid in a:
a[fqid].extend(information)
a[fqid]["entries"].extend(information["entries"])
if changed_fields := information.get("changed_fields"):
a[fqid].setdefault("changed_fields", dict()).update(changed_fields)
else:
a[fqid] = information
return a
13 changes: 9 additions & 4 deletions openslides_backend/action/actions/meeting_user/base_delete.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from openslides_backend.shared.history_events import build_history_information_data
from openslides_backend.shared.patterns import fqid_from_collection_and_id
from openslides_backend.shared.typing import HistoryInformation

Expand All @@ -17,9 +18,13 @@ class MeetingUserBaseDelete(DeleteAction):
def get_history_information(self) -> HistoryInformation | None:
users = self.get_instances_with_fields(["user_id", "meeting_id"])
return {
fqid_from_collection_and_id("user", user["user_id"]): [
"Participant removed from meeting {}",
fqid_from_collection_and_id("meeting", user["meeting_id"]),
]
fqid_from_collection_and_id(
"user", user["user_id"]
): build_history_information_data(
[
"Participant removed from meeting {}",
fqid_from_collection_and_id("meeting", user["meeting_id"]),
],
)
for user in users
}
17 changes: 10 additions & 7 deletions openslides_backend/action/actions/meeting_user/create.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Any

from openslides_backend.shared.exceptions import ActionException
from openslides_backend.shared.history_events import update_history_information
from openslides_backend.shared.patterns import fqid_from_collection_and_id
from openslides_backend.shared.typing import HistoryInformation

Expand Down Expand Up @@ -51,9 +52,9 @@ def update_instance(self, instance: dict[str, Any]) -> dict[str, Any]:
return super().update_instance(instance)

def get_history_information(self) -> HistoryInformation | None:
information = {}
information: HistoryInformation = {}
for instance in self.instances:
instance_information = []
entries = []
fqids_per_collection = {
collection_name: [
fqid_from_collection_and_id(
Expand All @@ -65,15 +66,17 @@ def get_history_information(self) -> HistoryInformation | None:
for collection_name in ["group", "structure_level"]
if (ids := instance.get(f"{collection_name}_ids"))
}
instance_information.append(
entries.append(
self.compose_history_string(list(fqids_per_collection.items()))
)
for collection_name, fqids in fqids_per_collection.items():
instance_information.extend(fqids)
instance_information.append(
entries.extend(fqids)
entries.append(
fqid_from_collection_and_id("meeting", instance["meeting_id"]),
)
information[fqid_from_collection_and_id("user", instance["user_id"])] = (
instance_information
update_history_information(
information,
fqid_from_collection_and_id("user", instance["user_id"]),
entries,
)
return information
101 changes: 80 additions & 21 deletions openslides_backend/action/actions/meeting_user/history_mixin.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
from collections.abc import Iterable
from copy import deepcopy
from typing import Any
from typing import Any, NotRequired, TypedDict

from openslides_backend.action.mixins.extend_history_mixin import ExtendHistoryMixin
from openslides_backend.shared.filters import FilterOperator
from openslides_backend.shared.history_events import build_history_information_data
from openslides_backend.shared.interfaces.event import Event, EventType

from ....services.database.interface import GetManyRequest
from ....shared.patterns import fqid_from_collection_and_id
from ....shared.patterns import Field, FullQualifiedId, fqid_from_collection_and_id
from ....shared.typing import HistoryInformation
from ...action import Action


class ActionHistoryInformationData(TypedDict):
entries: list[tuple[str, ...]]
changed_fields: NotRequired[dict[Field, Any]]


ActionHistoryInformation = dict[FullQualifiedId, ActionHistoryInformationData]


class MeetingUserHistoryMixin(ExtendHistoryMixin, Action):
extend_history_to = "user_id"

Expand Down Expand Up @@ -76,7 +86,7 @@ def create_events(self, instance: dict[str, Any]) -> Iterable[Event]:
)

def get_history_information(self) -> HistoryInformation | None:
information: dict[str, list[tuple[str, ...]]] = {}
information: ActionHistoryInformation = {}

# Scan the instances and collect the info for the history information
# Copy instances first since they are modified
Expand All @@ -97,17 +107,21 @@ def get_history_information(self) -> HistoryInformation | None:
)

return {
fqid: [string for entry in history for string in entry]
fqid: build_history_information_data(
[string for entry in history.get("entries", []) for string in entry],
history.get("changed_fields", {}),
)
for fqid, history in information.items()
}

def add_updated_meeting_user_history_information(
self,
instance: dict[str, Any],
db_instance: dict[str, Any],
information: dict[str, list[tuple[str, ...]]],
information: ActionHistoryInformation,
) -> None:
instance_information: list[tuple[str, ...]] = []
instance_entries: list[tuple[str, ...]] = []
instance_changed_fields: dict[str, list[int]] = {}
user_id = db_instance["user_id"]
meeting_id = db_instance["meeting_id"]

Expand All @@ -120,25 +134,33 @@ def add_updated_meeting_user_history_information(
# meeting specific data
update_fields = ["structure_level_ids", "number", "vote_weight"]
if any(field in instance for field in update_fields):
instance_information.append(
instance_entries.append(
(
"Participant data updated in meeting {}",
fqid_from_collection_and_id("meeting", meeting_id),
)
)

self.handle_group_updates(instance_information, instance, db_instance)
self.handle_delegations(
information, instance_information, instance, db_instance
self.handle_group_updates(
instance_entries,
instance_changed_fields,
instance,
db_instance,
)
self.handle_delegations(information, instance_entries, instance, db_instance)

if instance_information:
if instance_entries or instance_changed_fields:
self.add_entries_to_history_information(
information, instance_information, for_user_id=user_id
information,
instance_entries,
for_user_id=user_id,
changed_fields=instance_changed_fields,
)

def add_created_meeting_user_history_information(
self, instance: dict[str, Any], information: dict[str, list[tuple[str, ...]]]
self,
instance: dict[str, Any],
information: ActionHistoryInformation,
) -> None:
db_instance = self.datastore.get(
fqid_from_collection_and_id(self.model.collection, instance["id"]),
Expand Down Expand Up @@ -175,15 +197,21 @@ def add_created_meeting_user_history_information(

if instance_information:
self.add_entries_to_history_information(
information, instance_information, for_user_id=db_instance["user_id"]
information,
instance_information,
for_user_id=db_instance["user_id"],
changed_fields={
"group_ids": self.get_changed_group_ids(db_instance["user_id"])
},
)

def add_entries_to_history_information(
self,
information: dict[str, list[tuple[str, ...]]],
information: ActionHistoryInformation,
entries: list[tuple[str, ...]],
for_user_id: int | None = None,
for_meeting_user_id: int | None = None,
changed_fields: dict[Field, Any] | None = None,
) -> None:
if not for_user_id:
if not for_meeting_user_id:
Expand All @@ -197,11 +225,17 @@ def add_entries_to_history_information(
user_id = for_user_id
fqid = fqid_from_collection_and_id("user", user_id)
if fqid not in information:
information[fqid] = entries
information[fqid] = {"entries": entries}
if changed_fields:
information[fqid]["changed_fields"] = changed_fields
else:
for entry in entries:
if entry not in information[fqid]:
information[fqid].append(entry)
if entry not in information[fqid]["entries"]:
information[fqid]["entries"].append(entry)
if changed_fields:
information[fqid].setdefault("changed_fields", dict()).update(
changed_fields
)

def compose_history_string(
self, fqids_per_collection: list[tuple[str, list[str]]]
Expand Down Expand Up @@ -231,7 +265,8 @@ def compose_history_string(

def handle_group_updates(
self,
instance_information: list[tuple[str, ...]],
entries: list[tuple[str, ...]],
changed_fields: dict[str, list[int]],
instance: dict[str, Any],
db_instance: dict[str, Any],
) -> None:
Expand All @@ -242,6 +277,11 @@ def handle_group_updates(
added = instance_group_ids - db_group_ids
removed = db_group_ids - instance_group_ids

if added or removed:
changed_fields["group_ids"] = self.get_changed_group_ids(
db_instance["user_id"], {meeting_id: instance["group_ids"]}
)

# remove default groups
meeting = self.datastore.get(
fqid_from_collection_and_id("meeting", meeting_id),
Expand Down Expand Up @@ -273,11 +313,11 @@ def handle_group_updates(
fqid_from_collection_and_id("meeting", meeting_id)
)
if group_information:
instance_information.append(tuple(group_information))
entries.append(tuple(group_information))

def handle_delegations(
self,
information: dict[str, list[tuple[str, ...]]],
information: ActionHistoryInformation,
instance_information: list[tuple[str, ...]],
instance: dict[str, Any],
db_instance: dict[str, Any],
Expand Down Expand Up @@ -447,3 +487,22 @@ def handle_delegations(
],
for_meeting_user_id=muser_id,
)

def get_changed_group_ids(
self, user_id: int, update_data: dict[int, list[int]] = {}
) -> list[int]:
db_groups: dict[int, dict[str, Any]] = self.datastore.filter(
"meeting_user",
FilterOperator("user_id", "=", user_id),
["meeting_id", "group_ids"],
lock_result=False,
)
changed_groups = [
(
updated_groups
if (updated_groups := update_data.get(db_data["meeting_id"]))
else db_data["group_ids"]
)
for db_data in db_groups.values()
]
return [id_ for group_ids in changed_groups for id_ in group_ids]
24 changes: 13 additions & 11 deletions openslides_backend/action/actions/motion/base_create_forwarded.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from psycopg.types.json import Jsonb

from openslides_backend.action.actions.motion.mixins import TextHashMixin
from openslides_backend.shared.history_events import update_history_information
from openslides_backend.shared.typing import HistoryInformation

from ....i18n.translator import Translator
Expand Down Expand Up @@ -641,22 +642,23 @@ def forward_mediafiles(
return instance

def get_history_information(self) -> HistoryInformation | None:
forwarded_entries = defaultdict(list)
information: HistoryInformation = {}
for instance in self.instances:
forwarded_entries[
fqid_from_collection_and_id("motion", instance["origin_id"])
].extend(
update_history_information(
information,
fqid_from_collection_and_id("motion", instance["origin_id"]),
[
"Forwarded to {}",
fqid_from_collection_and_id("meeting", instance["meeting_id"]),
]
],
)
return forwarded_entries | {
fqid_from_collection_and_id("motion", instance["id"]): [
"Motion created (forwarded)"
]
for instance in self.instances
}
for instance in self.instances:
update_history_information(
information,
fqid_from_collection_and_id("motion", instance["id"]),
["Motion created (forwarded)"],
)
return information

def check_can_forward_with_attachments(self) -> None:
organization = self.datastore.get(
Expand Down
Loading
Loading