implement space exceptions for base_mapdata_access

This commit is contained in:
Laura Klünder 2018-11-20 23:41:25 +01:00
parent 93af6fb951
commit cc9441b66b
3 changed files with 62 additions and 40 deletions

View file

@ -75,9 +75,6 @@ class EditorViewSet(ViewSet):
if not can_access_editor(request): if not can_access_editor(request):
raise PermissionDenied raise PermissionDenied
if not request.user_permissions.can_access_base_mapdata:
raise PermissionDenied
Level = request.changeset.wrap_model('Level') Level = request.changeset.wrap_model('Level')
Space = request.changeset.wrap_model('Space') Space = request.changeset.wrap_model('Space')
@ -86,6 +83,10 @@ class EditorViewSet(ViewSet):
if level is not None: if level is not None:
if space is not None: if space is not None:
raise ValidationError('Only level or space can be specified.') 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) 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) 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) space = get_object_or_404(qs.select_related('level', 'level__on_top_of'), pk=space)
level = space.level level = space.level
doors = [door for door in level.doors.filter(Door.q_for_request(request)).all() if not request.user_permissions.can_access_base_mapdata and not space.base_mapdata_accessible:
if door.geometry.intersects(space.geometry)] raise PermissionDenied
doors_space_geom = cascaded_union([door.geometry for door in doors]+[space.geometry])
levels, levels_on_top, levels_under = self._get_levels_pk(request, level.primary_level) if request.user_permissions.can_access_base_mapdata:
if level.on_top_of_id is not None: doors = [door for door in level.doors.filter(Door.q_for_request(request)).all()
levels = chain([level.pk], levels_on_top) if door.geometry.intersects(space.geometry)]
other_spaces = Space.objects.filter(space_q_for_request, level__pk__in=levels).prefetch_related('groups') 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) levels, levels_on_top, levels_under = self._get_levels_pk(request, level.primary_level)
other_spaces = [s for s in other_spaces if level.on_top_of_id is not None:
if s.geometry.intersects(doors_space_geom) and s.pk != space.pk] levels = chain([level.pk], levels_on_top)
all_other_spaces = other_spaces other_spaces = Space.objects.filter(space_q_for_request,
level__pk__in=levels).prefetch_related('groups')
if level.on_top_of_id is None: space = next(s for s in other_spaces if s.pk == space.pk)
other_spaces_lower = [s for s in other_spaces if s.level_id in levels_under] other_spaces = [s for s in other_spaces
other_spaces_upper = [s for s in other_spaces if s.level_id in levels_on_top] 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: 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_upper = []
other_spaces = [s for s in other_spaces if s.level_id == level.pk] all_other_spaces = []
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
# todo: permissions # todo: permissions
graphnodes = request.changeset.wrap_model('GraphNode').objects.all() graphnodes = request.changeset.wrap_model('GraphNode').objects.all()

View file

@ -23,7 +23,7 @@ from c3nav.mapdata.models.access import AccessPermission
class EditorFormBase(I18nModelFormMixin, ModelForm): 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 self.request = request
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
creating = not self.instance.pk creating = not self.instance.pk
@ -41,7 +41,7 @@ class EditorFormBase(I18nModelFormMixin, ModelForm):
self.fields['space'].widget = HiddenInput() self.fields['space'].widget = HiddenInput()
if 'geometry' in self.fields: 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 # can't see this geometry in editor
self.fields.pop('geometry') self.fields.pop('geometry')
else: else:

View file

@ -95,7 +95,9 @@ def space_detail(request, level, pk):
qs = Space.objects.filter(Space.q_for_request(request)) qs = Space.objects.filter(Space.q_for_request(request))
space = get_object_or_404(qs.select_related('level'), level__pk=level, pk=pk) 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', submodels = ('POI', 'Area', 'Obstacle', 'LineObstacle', 'Stair', 'Ramp', 'Column',
'Hole', 'AltitudeMarker', 'LeaveDescription', 'CrossDescription', 'Hole', 'AltitudeMarker', 'LeaveDescription', 'CrossDescription',
'WifiMeasurement') 'WifiMeasurement')
@ -107,12 +109,12 @@ def space_detail(request, level, pk):
'level': space.level, 'level': space.level,
'level_url': 'editor.spaces.list', 'level_url': 'editor.spaces.list',
'space': space, '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) 'child_models': [child_model(request, model_name, kwargs={'space': pk}, parent=space)
for model_name in submodels], for model_name in submodels],
'geometry_url': ('/api/editor/geometries/?space='+pk '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 space_id = None
force_geometry_editable = False
if model == Level: if model == Level:
ctx.update({ ctx.update({
'level': obj, '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: if not new:
space = obj.space space = obj.space
space_id = space.pk space_id = space.pk
force_geometry_editable = (request.user_permissions.can_access_base_mapdata or space.base_mapdata_accessible)
ctx.update({ ctx.update({
'level': space.level, 'level': space.level,
'back_url': reverse('editor.'+related_name+'.list', kwargs={'space': space.pk}), 'back_url': reverse('editor.'+related_name+'.list', kwargs={'space': space.pk}),
'geometry_url': ('/api/editor/geometries/?space='+str(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: else:
kwargs = {} 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.')) messages.error(request, _('You can not edit this object because your changeset is full.'))
return redirect(request.path) 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': if not new and request.POST.get('delete') == '1':
# Delete this mapitem! # Delete this mapitem!
try: 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) return render(request, 'editor/delete.html', ctx)
form = model.EditorForm(instance=model() if new else obj, data=request.POST, 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(): if form.is_valid():
# Update/create objects # Update/create objects
obj = form.save(commit=False) 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.')) messages.error(request, _('You can not edit changes on this changeset.'))
else: 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({ ctx.update({
'form': form, 'form': form,