From 376709588eab15fd8c333c9d104b7c91add55a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sat, 8 Dec 2018 23:15:37 +0100 Subject: [PATCH] respect space_accesses in editor review process (some users can reviews some changes) --- src/c3nav/control/middleware.py | 14 ++++- src/c3nav/editor/models/changeset.py | 80 +++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/c3nav/control/middleware.py b/src/c3nav/control/middleware.py index 0d41b344..03e257c1 100644 --- a/src/c3nav/control/middleware.py +++ b/src/c3nav/control/middleware.py @@ -1,6 +1,6 @@ -from django.utils.functional import SimpleLazyObject +from django.utils.functional import SimpleLazyObject, lazy -from c3nav.control.models import UserPermissions +from c3nav.control.models import UserPermissions, UserSpaceAccess class UserPermissionsMiddleware: @@ -19,6 +19,16 @@ class UserPermissionsMiddleware: self._user_permissions_cache = result return result + def get_user_space_accesses(self, request): + try: + return getattr(request, '_user_space_accesses_cache') + except AttributeError: + pass + result = UserSpaceAccess.get_for_user(request.user) + self._user_space_accesses_cache = result + return result + def __call__(self, request): request.user_permissions = SimpleLazyObject(lambda: self.get_user_permissions(request)) + request.user_space_accesses = lazy(self.get_user_space_accesses, dict)(request) return self.get_response(request) diff --git a/src/c3nav/editor/models/changeset.py b/src/c3nav/editor/models/changeset.py index 11b9eb5e..499018b6 100644 --- a/src/c3nav/editor/models/changeset.py +++ b/src/c3nav/editor/models/changeset.py @@ -500,8 +500,86 @@ class ChangeSet(models.Model): def can_unpropose(self, request): return self.author_id == request.user.pk and self.state in ('proposed', 'reproposed') + def has_space_access_on_all_objects(self, request, force=False): + if not request.user.is_authenticated: + return False + + try: + request._has_space_access_on_all_objects_cache + except AttributeError: + request._has_space_access_on_all_objects_cache = {} + + can_edit_spaces = {space_id for space_id, can_edit in request.user_space_accesses.items() if can_edit} + + if not can_edit_spaces: + return False + + if not force: + try: + return request._has_space_access_on_all_objects_cache[self.pk] + except KeyError: + pass + + self.fill_changes_cache() + for model in self.changed_objects.keys(): + if issubclass(model, LocationRedirect): + continue + try: + model._meta.get_field('space') + except FieldDoesNotExist: + return False + + result = True + for model, objects in self.get_objects(many=False).items(): + if issubclass(model, (LocationRedirect, LocationSlug)): + continue + + try: + model._meta.get_field('space') + except FieldDoesNotExist: + result = False + break + + for obj in objects: + if obj.space_id not in can_edit_spaces: + result = False + break + if not result: + break + + try: + model._meta.get_field('origin_space') + except FieldDoesNotExist: + pass + else: + for obj in objects: + if obj.origin_space_id not in can_edit_spaces: + result = False + break + if not result: + break + + try: + model._meta.get_field('target_space') + except FieldDoesNotExist: + pass + else: + for obj in objects: + if obj.target_space_id not in can_edit_spaces: + result = False + break + if not result: + break + + request._has_space_access_on_all_objects_cache[self.pk] = result + return result + def can_review(self, request): - return request.user_permissions.review_changesets + if not request.user.is_authenticated: + return False + if request.user_permissions.review_changesets: + return True + return self.has_space_access_on_all_objects(request) @classmethod def can_direct_edit(cls, request):