diff --git a/src/c3nav/editor/api.py b/src/c3nav/editor/api.py index ce3501e8..2ad9abfd 100644 --- a/src/c3nav/editor/api.py +++ b/src/c3nav/editor/api.py @@ -75,9 +75,6 @@ class EditorViewSet(ViewSet): if not can_access_editor(request): raise PermissionDenied - if not request.user_permissions.can_access_base_mapdata: - raise PermissionDenied - Level = request.changeset.wrap_model('Level') Space = request.changeset.wrap_model('Space') @@ -86,6 +83,10 @@ class EditorViewSet(ViewSet): if level is not None: if space is not None: raise ValidationError('Only level or space can be specified.') + + if not request.user_permissions.can_access_base_mapdata: + raise PermissionDenied + level = get_object_or_404(Level.objects.filter(Level.q_for_request(request)), pk=level) levels, levels_on_top, levels_under = self._get_levels_pk(request, level) @@ -140,40 +141,52 @@ class EditorViewSet(ViewSet): space = get_object_or_404(qs.select_related('level', 'level__on_top_of'), pk=space) level = space.level - doors = [door for door in level.doors.filter(Door.q_for_request(request)).all() - if door.geometry.intersects(space.geometry)] - doors_space_geom = cascaded_union([door.geometry for door in doors]+[space.geometry]) + if not request.user_permissions.can_access_base_mapdata and not space.base_mapdata_accessible: + raise PermissionDenied - levels, levels_on_top, levels_under = self._get_levels_pk(request, level.primary_level) - if level.on_top_of_id is not None: - levels = chain([level.pk], levels_on_top) - other_spaces = Space.objects.filter(space_q_for_request, level__pk__in=levels).prefetch_related('groups') + if request.user_permissions.can_access_base_mapdata: + doors = [door for door in level.doors.filter(Door.q_for_request(request)).all() + if door.geometry.intersects(space.geometry)] + doors_space_geom = cascaded_union([door.geometry for door in doors]+[space.geometry]) - space = next(s for s in other_spaces if s.pk == space.pk) - other_spaces = [s for s in other_spaces - if s.geometry.intersects(doors_space_geom) and s.pk != space.pk] - all_other_spaces = other_spaces + levels, levels_on_top, levels_under = self._get_levels_pk(request, level.primary_level) + if level.on_top_of_id is not None: + levels = chain([level.pk], levels_on_top) + other_spaces = Space.objects.filter(space_q_for_request, + level__pk__in=levels).prefetch_related('groups') - if level.on_top_of_id is None: - other_spaces_lower = [s for s in other_spaces if s.level_id in levels_under] - other_spaces_upper = [s for s in other_spaces if s.level_id in levels_on_top] + space = next(s for s in other_spaces if s.pk == space.pk) + other_spaces = [s for s in other_spaces + if s.geometry.intersects(doors_space_geom) and s.pk != space.pk] + all_other_spaces = other_spaces + + if level.on_top_of_id is None: + other_spaces_lower = [s for s in other_spaces if s.level_id in levels_under] + other_spaces_upper = [s for s in other_spaces if s.level_id in levels_on_top] + else: + other_spaces_lower = [s for s in other_spaces if s.level_id == level.on_top_of_id] + other_spaces_upper = [] + other_spaces = [s for s in other_spaces if s.level_id == level.pk] + + space.bounds = True + + buildings = level.buildings.all() + buildings_geom = cascaded_union([building.geometry for building in buildings]) + for other_space in other_spaces: + if other_space.outside: + other_space.geometry = other_space.geometry.difference(buildings_geom) + for other_space in chain(other_spaces, other_spaces_lower, other_spaces_upper): + other_space.opacity = 0.4 + other_space.color = '#ffffff' + for building in buildings: + building.opacity = 0.5 else: - other_spaces_lower = [s for s in other_spaces if s.level_id == level.on_top_of_id] + buildings = [] + doors = [] + other_spaces = [] + other_spaces_lower = [] other_spaces_upper = [] - other_spaces = [s for s in other_spaces if s.level_id == level.pk] - - space.bounds = True - - buildings = level.buildings.all() - buildings_geom = cascaded_union([building.geometry for building in buildings]) - for other_space in other_spaces: - if other_space.outside: - other_space.geometry = other_space.geometry.difference(buildings_geom) - for other_space in chain(other_spaces, other_spaces_lower, other_spaces_upper): - other_space.opacity = 0.4 - other_space.color = '#ffffff' - for building in buildings: - building.opacity = 0.5 + all_other_spaces = [] # todo: permissions graphnodes = request.changeset.wrap_model('GraphNode').objects.all() diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index e60e2024..db5c9efe 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -23,7 +23,7 @@ from c3nav.mapdata.models.access import AccessPermission class EditorFormBase(I18nModelFormMixin, ModelForm): - def __init__(self, *args, space_id=None, request=None, **kwargs): + def __init__(self, *args, space_id=None, request=None, force_geometry_editable=False, **kwargs): self.request = request super().__init__(*args, **kwargs) creating = not self.instance.pk @@ -41,7 +41,7 @@ class EditorFormBase(I18nModelFormMixin, ModelForm): self.fields['space'].widget = HiddenInput() if 'geometry' in self.fields: - if not request.user_permissions.can_access_base_mapdata: + if not request.user_permissions.can_access_base_mapdata and not force_geometry_editable: # can't see this geometry in editor self.fields.pop('geometry') else: diff --git a/src/c3nav/editor/views/edit.py b/src/c3nav/editor/views/edit.py index 496c426a..549fe785 100644 --- a/src/c3nav/editor/views/edit.py +++ b/src/c3nav/editor/views/edit.py @@ -95,7 +95,9 @@ def space_detail(request, level, pk): qs = Space.objects.filter(Space.q_for_request(request)) space = get_object_or_404(qs.select_related('level'), level__pk=level, pk=pk) - if request.user_permissions.can_access_base_mapdata: + can_edit = request.user_permissions.can_access_base_mapdata or space.base_mapdata_accessible + + if can_edit: submodels = ('POI', 'Area', 'Obstacle', 'LineObstacle', 'Stair', 'Ramp', 'Column', 'Hole', 'AltitudeMarker', 'LeaveDescription', 'CrossDescription', 'WifiMeasurement') @@ -107,12 +109,12 @@ def space_detail(request, level, pk): 'level': space.level, 'level_url': 'editor.spaces.list', 'space': space, - 'can_edit_graph': request.user_permissions.can_access_base_mapdata, + 'can_edit_graph': can_edit, 'child_models': [child_model(request, model_name, kwargs={'space': pk}, parent=space) for model_name in submodels], 'geometry_url': ('/api/editor/geometries/?space='+pk - if request.user_permissions.can_access_base_mapdata else None), + if can_edit else None), }) @@ -185,6 +187,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e }) space_id = None + force_geometry_editable = False if model == Level: ctx.update({ 'level': obj, @@ -234,11 +237,12 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e if not new: space = obj.space space_id = space.pk + force_geometry_editable = (request.user_permissions.can_access_base_mapdata or space.base_mapdata_accessible) ctx.update({ 'level': space.level, 'back_url': reverse('editor.'+related_name+'.list', kwargs={'space': space.pk}), 'geometry_url': ('/api/editor/geometries/?space='+str(space.pk) - if request.user_permissions.can_access_base_mapdata else None), + if force_geometry_editable else None), }) else: kwargs = {} @@ -280,6 +284,10 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e messages.error(request, _('You can not edit this object because your changeset is full.')) return redirect(request.path) + if not can_edit: + messages.error(request, _('You can not edit this object.')) + return redirect(request.path) + if not new and request.POST.get('delete') == '1': # Delete this mapitem! try: @@ -308,7 +316,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e return render(request, 'editor/delete.html', ctx) form = model.EditorForm(instance=model() if new else obj, data=request.POST, - request=request, space_id=space_id) + request=request, space_id=space_id, force_geometry_editable=force_geometry_editable) if form.is_valid(): # Update/create objects obj = form.save(commit=False) @@ -343,7 +351,8 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e messages.error(request, _('You can not edit changes on this changeset.')) else: - form = model.EditorForm(instance=obj, request=request, space_id=space_id) + form = model.EditorForm(instance=obj, request=request, space_id=space_id, + force_geometry_editable=force_geometry_editable) ctx.update({ 'form': form,