diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index 8c6c709a1..e25f00498 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -426,12 +426,12 @@ class SpeakerManager(models.Manager): list of speakers and that someone is twice on one list (off coming speakers). Cares also initial sorting of the coming speakers. """ + if isinstance(user, AnonymousUser): + raise OpenSlidesError("An anonymous user can not be on lists of speakers.") if self.filter( user=user, list_of_speakers=list_of_speakers, begin_time=None ).exists(): raise OpenSlidesError(f"{user} is already on the list of speakers.") - if isinstance(user, AnonymousUser): - raise OpenSlidesError("An anonymous user can not be on lists of speakers.") if config["agenda_present_speakers_only"] and not user.is_present: raise OpenSlidesError("Only present users can be on the lists of speakers.") weight = ( @@ -443,7 +443,11 @@ class SpeakerManager(models.Manager): speaker = self.model( list_of_speakers=list_of_speakers, user=user, weight=weight + 1 ) - speaker.save(force_insert=True, skip_autoupdate=skip_autoupdate) + speaker.save( + force_insert=True, + skip_autoupdate=skip_autoupdate, + no_delete_on_restriction=True, + ) return speaker diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py index 0d98122f9..9d60f3c70 100644 --- a/openslides/agenda/views.py +++ b/openslides/agenda/views.py @@ -356,8 +356,7 @@ class ListOfSpeakersViewSet( # Send new speaker via autoupdate because users without permission # to see users may not have it but can get it now. - inform_changed_data([user]) - # TODO: inform_changed_data(user) should work. But isinstance(user, Iterable) is true... + inform_changed_data(user, disable_history=True) # Toggle 'marked' for the speaker elif request.method == "PATCH": diff --git a/openslides/assignments/access_permissions.py b/openslides/assignments/access_permissions.py index 9a76c5bd5..33b684a9a 100644 --- a/openslides/assignments/access_permissions.py +++ b/openslides/assignments/access_permissions.py @@ -1,11 +1,8 @@ -from typing import Any, Dict, List - from ..poll.access_permissions import ( BasePollAccessPermissions, BaseVoteAccessPermissions, ) from ..utils.access_permissions import BaseAccessPermissions -from ..utils.auth import async_has_perm class AssignmentAccessPermissions(BaseAccessPermissions): @@ -15,38 +12,6 @@ class AssignmentAccessPermissions(BaseAccessPermissions): base_permission = "assignments.can_see" - async def get_restricted_data( - self, full_data: List[Dict[str, Any]], user_id: int - ) -> List[Dict[str, Any]]: - """ - Returns the restricted serialized data for the instance prepared - for the user. Removes unpublished polls for non admins so that they - only get a result like the AssignmentShortSerializer would give them. - """ - # Parse data. - if await async_has_perm( - user_id, "assignments.can_see" - ) and await async_has_perm(user_id, "assignments.can_manage"): - data = full_data - elif await async_has_perm(user_id, "assignments.can_see"): - # Exclude unpublished poll votes. - data = [] - for full in full_data: - full_copy = full.copy() - polls = full_copy["polls"] - for poll in polls: - if not poll["published"]: - for option in poll["options"]: - option["votes"] = [] # clear votes for not published polls - poll[ - "has_votes" - ] = False # A user should see, if there are votes. - data.append(full_copy) - else: - data = [] - - return data - class AssignmentPollAccessPermissions(BasePollAccessPermissions): base_permission = "assignments.can_see" diff --git a/openslides/utils/autoupdate.py b/openslides/utils/autoupdate.py index 5aeabde67..7701b1598 100644 --- a/openslides/utils/autoupdate.py +++ b/openslides/utils/autoupdate.py @@ -9,7 +9,7 @@ from mypy_extensions import TypedDict from .cache import element_cache, get_element_id from .projector import get_projector_data -from .utils import get_model_from_collection_string +from .utils import get_model_from_collection_string, is_iterable class AutoupdateElementBase(TypedDict): @@ -150,6 +150,7 @@ def inform_changed_data( instances: Union[Iterable[Model], Model], information: List[str] = None, user_id: Optional[int] = None, + disable_history: bool = False, no_delete_on_restriction: bool = False, ) -> None: """ @@ -162,7 +163,7 @@ def inform_changed_data( """ if information is None: information = [] - if not isinstance(instances, Iterable): + if not is_iterable(instances): instances = (instances,) root_instances = set(instance.get_root_rest_element() for instance in instances) @@ -170,6 +171,7 @@ def inform_changed_data( AutoupdateElement( id=root_instance.get_rest_pk(), collection_string=root_instance.get_collection_string(), + disable_history=disable_history, information=information, user_id=user_id, no_delete_on_restriction=no_delete_on_restriction, diff --git a/openslides/utils/utils.py b/openslides/utils/utils.py index f739f1304..f068730be 100644 --- a/openslides/utils/utils.py +++ b/openslides/utils/utils.py @@ -72,6 +72,20 @@ def is_int(obj: Any) -> bool: return False +def is_iterable(obj: Any) -> bool: + """ + Do not rely on `isinstance(obj, Iterable` with `Iterable` being imperted + from typing. This breaks at proxyobjects, like SimpleLazyObjects from Django. + Instead try to get the iterable from the object. THis fails on non-iterable + proxyobjects. + """ + try: + iter(obj) + return True + except TypeError: + return False + + _models_to_collection_string: Dict[str, Type[Model]] = {}