Fix assignment access permissions

Also improves unnecessary history-savings of users in the list of speakers
This commit is contained in:
FinnStutzenstein 2019-11-05 11:26:43 +01:00
parent b50cf42543
commit fafb81daca
5 changed files with 26 additions and 42 deletions

View File

@ -426,12 +426,12 @@ class SpeakerManager(models.Manager):
list of speakers and that someone is twice on one list (off coming list of speakers and that someone is twice on one list (off coming
speakers). Cares also initial sorting of the coming speakers. 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( if self.filter(
user=user, list_of_speakers=list_of_speakers, begin_time=None user=user, list_of_speakers=list_of_speakers, begin_time=None
).exists(): ).exists():
raise OpenSlidesError(f"{user} is already on the list of speakers.") 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: if config["agenda_present_speakers_only"] and not user.is_present:
raise OpenSlidesError("Only present users can be on the lists of speakers.") raise OpenSlidesError("Only present users can be on the lists of speakers.")
weight = ( weight = (
@ -443,7 +443,11 @@ class SpeakerManager(models.Manager):
speaker = self.model( speaker = self.model(
list_of_speakers=list_of_speakers, user=user, weight=weight + 1 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 return speaker

View File

@ -356,8 +356,7 @@ class ListOfSpeakersViewSet(
# Send new speaker via autoupdate because users without permission # Send new speaker via autoupdate because users without permission
# to see users may not have it but can get it now. # to see users may not have it but can get it now.
inform_changed_data([user]) inform_changed_data(user, disable_history=True)
# TODO: inform_changed_data(user) should work. But isinstance(user, Iterable) is true...
# Toggle 'marked' for the speaker # Toggle 'marked' for the speaker
elif request.method == "PATCH": elif request.method == "PATCH":

View File

@ -1,11 +1,8 @@
from typing import Any, Dict, List
from ..poll.access_permissions import ( from ..poll.access_permissions import (
BasePollAccessPermissions, BasePollAccessPermissions,
BaseVoteAccessPermissions, BaseVoteAccessPermissions,
) )
from ..utils.access_permissions import BaseAccessPermissions from ..utils.access_permissions import BaseAccessPermissions
from ..utils.auth import async_has_perm
class AssignmentAccessPermissions(BaseAccessPermissions): class AssignmentAccessPermissions(BaseAccessPermissions):
@ -15,38 +12,6 @@ class AssignmentAccessPermissions(BaseAccessPermissions):
base_permission = "assignments.can_see" 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): class AssignmentPollAccessPermissions(BasePollAccessPermissions):
base_permission = "assignments.can_see" base_permission = "assignments.can_see"

View File

@ -9,7 +9,7 @@ from mypy_extensions import TypedDict
from .cache import element_cache, get_element_id from .cache import element_cache, get_element_id
from .projector import get_projector_data 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): class AutoupdateElementBase(TypedDict):
@ -150,6 +150,7 @@ def inform_changed_data(
instances: Union[Iterable[Model], Model], instances: Union[Iterable[Model], Model],
information: List[str] = None, information: List[str] = None,
user_id: Optional[int] = None, user_id: Optional[int] = None,
disable_history: bool = False,
no_delete_on_restriction: bool = False, no_delete_on_restriction: bool = False,
) -> None: ) -> None:
""" """
@ -162,7 +163,7 @@ def inform_changed_data(
""" """
if information is None: if information is None:
information = [] information = []
if not isinstance(instances, Iterable): if not is_iterable(instances):
instances = (instances,) instances = (instances,)
root_instances = set(instance.get_root_rest_element() for instance in instances) root_instances = set(instance.get_root_rest_element() for instance in instances)
@ -170,6 +171,7 @@ def inform_changed_data(
AutoupdateElement( AutoupdateElement(
id=root_instance.get_rest_pk(), id=root_instance.get_rest_pk(),
collection_string=root_instance.get_collection_string(), collection_string=root_instance.get_collection_string(),
disable_history=disable_history,
information=information, information=information,
user_id=user_id, user_id=user_id,
no_delete_on_restriction=no_delete_on_restriction, no_delete_on_restriction=no_delete_on_restriction,

View File

@ -72,6 +72,20 @@ def is_int(obj: Any) -> bool:
return False 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]] = {} _models_to_collection_string: Dict[str, Type[Model]] = {}