add new data and editor permissions
This commit is contained in:
parent
8ffa982882
commit
b88b6c3a29
18 changed files with 160 additions and 60 deletions
|
@ -1,3 +1,4 @@
|
|||
import inspect
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
||||
|
@ -14,6 +15,7 @@ from c3nav.mapdata.api import (AccessRestrictionGroupViewSet, AccessRestrictionV
|
|||
LocationGroupCategoryViewSet, LocationGroupViewSet, LocationViewSet, MapViewSet,
|
||||
ObstacleViewSet, POIViewSet, RampViewSet, SourceViewSet, SpaceViewSet, StairViewSet,
|
||||
UpdatesViewSet)
|
||||
from c3nav.mapdata.utils.user import can_access_editor
|
||||
from c3nav.routing.api import RoutingViewSet
|
||||
|
||||
router = SimpleRouter()
|
||||
|
@ -62,8 +64,11 @@ class APIRoot(GenericAPIView):
|
|||
|
||||
@cached_property
|
||||
def urls(self):
|
||||
include_editor = can_access_editor(self.request)
|
||||
urls = OrderedDict()
|
||||
for urlpattern in router.urls:
|
||||
if not include_editor and inspect.getmodule(urlpattern.callback).__name__.startswith('c3nav.editor.'):
|
||||
continue
|
||||
name = urlpattern.name
|
||||
url = self._format_pattern(str(urlpattern.pattern)).replace('{pk}', '{id}')
|
||||
base = url.split('/', 1)[0]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 2.1.1 on 2018-09-19 15:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('control', '0004_more_user_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userpermissions',
|
||||
name='base_mapdata_access',
|
||||
field=models.BooleanField(default=False, verbose_name='can always access base map data'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userpermissions',
|
||||
name='editor_access',
|
||||
field=models.BooleanField(default=False, verbose_name='can always access editor'),
|
||||
),
|
||||
]
|
|
@ -14,6 +14,8 @@ class UserPermissions(models.Model):
|
|||
review_changesets = models.BooleanField(default=False, verbose_name=_('can review changesets'))
|
||||
direct_edit = models.BooleanField(default=False, verbose_name=_('can activate direct editing'))
|
||||
max_changeset_changes = models.PositiveSmallIntegerField(default=10, verbose_name=_('max changes per changeset'))
|
||||
editor_access = models.BooleanField(default=False, verbose_name=_('can always access editor'))
|
||||
base_mapdata_access = models.BooleanField(default=False, verbose_name=_('can always access base map data'))
|
||||
|
||||
control_panel = models.BooleanField(default=False, verbose_name=_('can access control panel'))
|
||||
grant_permissions = models.BooleanField(default=False, verbose_name=_('can grant control permissions'))
|
||||
|
|
|
@ -2,7 +2,7 @@ from itertools import chain
|
|||
|
||||
from django.db.models import Prefetch, Q
|
||||
from rest_framework.decorators import detail_route, list_route
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
|
||||
|
@ -13,6 +13,7 @@ from c3nav.editor.views.base import etag_func
|
|||
from c3nav.mapdata.api import api_etag
|
||||
from c3nav.mapdata.models import Area, Door, MapUpdate, Source
|
||||
from c3nav.mapdata.models.geometry.space import POI
|
||||
from c3nav.mapdata.utils.user import can_access_editor
|
||||
|
||||
|
||||
class EditorViewSet(ViewSet):
|
||||
|
@ -71,6 +72,9 @@ class EditorViewSet(ViewSet):
|
|||
@list_route(methods=['get'])
|
||||
@api_etag(etag_func=etag_func, cache_parameters={'level': str, 'space': str})
|
||||
def geometries(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
|
||||
Level = request.changeset.wrap_model('Level')
|
||||
Space = request.changeset.wrap_model('Space')
|
||||
|
||||
|
@ -209,6 +213,9 @@ class EditorViewSet(ViewSet):
|
|||
@list_route(methods=['get'])
|
||||
@api_etag(etag_func=MapUpdate.current_cache_key, cache_parameters={})
|
||||
def geometrystyles(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
|
||||
return Response({
|
||||
'building': '#aaaaaa',
|
||||
'space': '#eeeeee',
|
||||
|
@ -231,6 +238,9 @@ class EditorViewSet(ViewSet):
|
|||
@list_route(methods=['get'])
|
||||
@api_etag(etag_func=etag_func, cache_parameters={})
|
||||
def bounds(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
|
||||
return Response({
|
||||
'bounds': Source.max_bounds(),
|
||||
})
|
||||
|
@ -247,18 +257,26 @@ class ChangeSetViewSet(ReadOnlyModelViewSet):
|
|||
return ChangeSet.qs_for_request(self.request).select_related('last_update', 'last_state_update', 'last_change')
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
return Response([obj.serialize() for obj in self.get_queryset().order_by('id')])
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
return Response(self.get_object().serialize())
|
||||
|
||||
@list_route(methods=['get'])
|
||||
def current(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
changeset = ChangeSet.get_for_request(request)
|
||||
return Response(changeset.serialize())
|
||||
|
||||
@detail_route(methods=['get'])
|
||||
def changes(self, request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
return PermissionDenied
|
||||
changeset = self.get_object()
|
||||
changeset.fill_changes_cache()
|
||||
return Response([obj.serialize() for obj in changeset.iter_changed_objects()])
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from functools import wraps
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponseNotModified, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.utils.cache import patch_vary_headers
|
||||
|
@ -7,6 +8,7 @@ from django.utils.translation import get_language
|
|||
|
||||
from c3nav.editor.models import ChangeSet
|
||||
from c3nav.mapdata.models.access import AccessPermission
|
||||
from c3nav.mapdata.utils.user import can_access_editor
|
||||
|
||||
|
||||
def sidebar_view(func=None, select_related=None):
|
||||
|
@ -17,6 +19,9 @@ def sidebar_view(func=None, select_related=None):
|
|||
|
||||
@wraps(func)
|
||||
def with_ajax_check(request, *args, **kwargs):
|
||||
if not can_access_editor(request):
|
||||
raise PermissionDenied
|
||||
|
||||
request.changeset = ChangeSet.get_for_request(request, select_related)
|
||||
|
||||
ajax = request.is_ajax() or 'ajax' in request.GET
|
||||
|
|
|
@ -29,7 +29,7 @@ from c3nav.mapdata.models.locations import (Location, LocationGroupCategory, Loc
|
|||
from c3nav.mapdata.utils.locations import (get_location_by_id_for_request, get_location_by_slug_for_request,
|
||||
searchable_locations_for_request, visible_locations_for_request)
|
||||
from c3nav.mapdata.utils.models import get_submodels
|
||||
from c3nav.mapdata.utils.user import get_user_data
|
||||
from c3nav.mapdata.utils.user import can_access_base_mapdata, can_access_editor, get_user_data
|
||||
from c3nav.mapdata.views import set_tile_access_cookie
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ def optimize_query(qs):
|
|||
return qs
|
||||
|
||||
|
||||
def api_etag(permissions=True, etag_func=AccessPermission.etag_func, cache_parameters=None):
|
||||
def api_etag(permissions=True, etag_func=AccessPermission.etag_func, cache_parameters=None, base_mapdata_check=False):
|
||||
def wrapper(func):
|
||||
@wraps(func)
|
||||
def wrapped_func(self, request, *args, **kwargs):
|
||||
|
@ -50,6 +50,8 @@ def api_etag(permissions=True, etag_func=AccessPermission.etag_func, cache_param
|
|||
etag_user = (':'+str(request.user.pk or 0)) if response_format == 'api' else ''
|
||||
raw_etag = '%s%s:%s:%s' % (response_format, etag_user, get_language(),
|
||||
(etag_func(request) if permissions else MapUpdate.current_cache_key()))
|
||||
if base_mapdata_check and self.base_mapdata:
|
||||
raw_etag += ':%d' % can_access_base_mapdata(request)
|
||||
etag = quote_etag(raw_etag)
|
||||
|
||||
response = get_conditional_response(request, etag=etag)
|
||||
|
@ -68,8 +70,9 @@ def api_etag(permissions=True, etag_func=AccessPermission.etag_func, cache_param
|
|||
if cache_parameters is not None and response.status_code == 200:
|
||||
cache.set(cache_key, response.data, 300)
|
||||
|
||||
response['ETag'] = etag
|
||||
response['Cache-Control'] = 'no-cache'
|
||||
if response.status_code == 200:
|
||||
response['ETag'] = etag
|
||||
response['Cache-Control'] = 'no-cache'
|
||||
return response
|
||||
return wrapped_func
|
||||
return wrapper
|
||||
|
@ -90,6 +93,7 @@ class MapViewSet(ViewSet):
|
|||
|
||||
|
||||
class MapdataViewSet(ReadOnlyModelViewSet):
|
||||
base_mapdata = False
|
||||
order_by = ('id', )
|
||||
|
||||
def get_queryset(self):
|
||||
|
@ -98,6 +102,12 @@ class MapdataViewSet(ReadOnlyModelViewSet):
|
|||
return qs.model.qs_for_request(self.request)
|
||||
return qs
|
||||
|
||||
@staticmethod
|
||||
def can_access_geometry(request, obj):
|
||||
if isinstance(obj, (Building, Space, Door)):
|
||||
return can_access_base_mapdata(request)
|
||||
return True
|
||||
|
||||
qs_filter = namedtuple('qs_filter', ('field', 'model', 'key', 'value'))
|
||||
|
||||
def _get_keys_for_model(self, request, model, key):
|
||||
|
@ -165,16 +175,19 @@ class MapdataViewSet(ReadOnlyModelViewSet):
|
|||
cache.set(cache_key, results, 300)
|
||||
return results
|
||||
|
||||
@api_etag()
|
||||
@api_etag(base_mapdata_check=True)
|
||||
def list(self, request, *args, **kwargs):
|
||||
geometry = ('geometry' in request.GET)
|
||||
geometry = 'geometry' in request.GET
|
||||
results = self._get_list(request)
|
||||
if results:
|
||||
geometry = geometry and self.can_access_geometry(request, results[0])
|
||||
|
||||
return Response([obj.serialize(geometry=geometry) for obj in results])
|
||||
|
||||
@api_etag()
|
||||
@api_etag(base_mapdata_check=True)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
return Response(self.get_object().serialize())
|
||||
obj = self.get_object()
|
||||
return Response(obj.serialize(geometry=self.can_access_geometry(request, obj)))
|
||||
|
||||
@staticmethod
|
||||
def list_types(models_list, **kwargs):
|
||||
|
@ -197,16 +210,18 @@ class LevelViewSet(MapdataViewSet):
|
|||
|
||||
|
||||
class BuildingViewSet(MapdataViewSet):
|
||||
""" Add ?geometry=1 to get geometries, add ?level=<id> to filter by level. """
|
||||
""" Add ?geometry=1 to get geometries if available, add ?level=<id> to filter by level. """
|
||||
queryset = Building.objects.all()
|
||||
base_mapdata = True
|
||||
|
||||
|
||||
class SpaceViewSet(MapdataViewSet):
|
||||
"""
|
||||
Add ?geometry=1 to get geometries, add ?level=<id> to filter by level, add ?group=<id> to filter by group.
|
||||
Add ?geometry=1 to get geometries if available, ?level=<id> to filter by level, ?group=<id> to filter by group.
|
||||
A Space is a Location – so if it is visible, you can use its ID in the Location API as well.
|
||||
"""
|
||||
queryset = Space.objects.all()
|
||||
base_mapdata = True
|
||||
|
||||
@list_route(methods=['get'])
|
||||
@api_etag(permissions=False, cache_parameters={})
|
||||
|
@ -215,8 +230,9 @@ class SpaceViewSet(MapdataViewSet):
|
|||
|
||||
|
||||
class DoorViewSet(MapdataViewSet):
|
||||
""" Add ?geometry=1 to get geometries, add ?level=<id> to filter by level. """
|
||||
""" Add ?geometry=1 to get geometries if available, add ?level=<id> to filter by level. """
|
||||
queryset = Door.objects.all()
|
||||
base_mapdata = True
|
||||
|
||||
|
||||
class HoleViewSet(MapdataViewSet):
|
||||
|
@ -287,11 +303,12 @@ class LocationGroupViewSet(MapdataViewSet):
|
|||
|
||||
class LocationViewSetBase(RetrieveModelMixin, GenericViewSet):
|
||||
queryset = LocationSlug.objects.all()
|
||||
base_mapdata = True
|
||||
|
||||
def get_object(self) -> LocationSlug:
|
||||
raise NotImplementedError
|
||||
|
||||
@api_etag(cache_parameters={'show_redirects': bool, 'detailed': bool, 'geometry': bool})
|
||||
@api_etag(cache_parameters={'show_redirects': bool, 'detailed': bool, 'geometry': bool}, base_mapdata_check=True)
|
||||
def retrieve(self, request, key=None, *args, **kwargs):
|
||||
show_redirects = 'show_redirects' in request.GET
|
||||
detailed = 'detailed' in request.GET
|
||||
|
@ -307,10 +324,11 @@ class LocationViewSetBase(RetrieveModelMixin, GenericViewSet):
|
|||
return redirect('../' + str(location.target.slug)) # todo: why does redirect/reverse not work here?
|
||||
|
||||
return Response(location.serialize(include_type=True, detailed=detailed,
|
||||
geometry=geometry, simple_geometry=True))
|
||||
geometry=geometry and MapdataViewSet.can_access_geometry(request, location),
|
||||
simple_geometry=True))
|
||||
|
||||
@detail_route(methods=['get'])
|
||||
@api_etag()
|
||||
@api_etag(base_mapdata_check=True)
|
||||
def details(self, request, **kwargs):
|
||||
location = self.get_object()
|
||||
|
||||
|
@ -320,7 +338,10 @@ class LocationViewSetBase(RetrieveModelMixin, GenericViewSet):
|
|||
if isinstance(location, LocationRedirect):
|
||||
return redirect('../' + str(location.target.pk) + '/details/')
|
||||
|
||||
return Response(location.details_display())
|
||||
return Response(location.details_display(
|
||||
detailed_geometry=MapdataViewSet.can_access_geometry(request, location),
|
||||
editor_url=can_access_editor(request)
|
||||
))
|
||||
|
||||
|
||||
class LocationViewSet(LocationViewSetBase):
|
||||
|
@ -332,7 +353,7 @@ class LocationViewSet(LocationViewSetBase):
|
|||
|
||||
add ?searchable to only show locations with can_search set to true ordered by relevance
|
||||
add ?detailed to show all attributes
|
||||
add ?geometry to show geometries
|
||||
add ?geometry to show geometries if available
|
||||
/{id}/ add ?show_redirect=1 to suppress redirects and show them as JSON.
|
||||
also possible: /by_slug/{slug}/
|
||||
"""
|
||||
|
@ -342,24 +363,27 @@ class LocationViewSet(LocationViewSetBase):
|
|||
def get_object(self):
|
||||
return get_location_by_id_for_request(self.kwargs['pk'], self.request)
|
||||
|
||||
@api_etag(cache_parameters={'searchable': bool, 'detailed': bool, 'geometry': bool})
|
||||
@api_etag(cache_parameters={'searchable': bool, 'detailed': bool, 'geometry': bool}, base_mapdata_check=True)
|
||||
def list(self, request, *args, **kwargs):
|
||||
searchable = 'searchable' in request.GET
|
||||
detailed = 'detailed' in request.GET
|
||||
geometry = 'geometry' in request.GET
|
||||
|
||||
cache_key = 'mapdata:api:location:list:%d:%s' % (
|
||||
cache_key = 'mapdata:api:location:list:%d:%s:%d' % (
|
||||
searchable + detailed*2 + geometry*4,
|
||||
AccessPermission.cache_key_for_request(self.request)
|
||||
AccessPermission.cache_key_for_request(request),
|
||||
can_access_base_mapdata(request)
|
||||
)
|
||||
result = cache.get(cache_key, None)
|
||||
if result is None:
|
||||
if searchable:
|
||||
locations = searchable_locations_for_request(self.request)
|
||||
locations = searchable_locations_for_request(request)
|
||||
else:
|
||||
locations = visible_locations_for_request(self.request).values()
|
||||
locations = visible_locations_for_request(request).values()
|
||||
|
||||
result = tuple(obj.serialize(include_type=True, detailed=detailed, geometry=geometry, simple_geometry=True)
|
||||
result = tuple(obj.serialize(include_type=True, detailed=detailed,
|
||||
geometry=geometry and MapdataViewSet.can_access_geometry(request, obj),
|
||||
simple_geometry=True)
|
||||
for obj in locations)
|
||||
cache.set(cache_key, result, 300)
|
||||
|
||||
|
|
|
@ -250,8 +250,8 @@ class AccessRestrictionMixin(SerializableMixin, models.Model):
|
|||
result['access_restriction'] = self.access_restriction_id
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].extend([
|
||||
(_('Access Restriction'), self.access_restriction_id and self.access_restriction.title),
|
||||
])
|
||||
|
|
|
@ -33,7 +33,7 @@ class SerializableMixin(models.Model):
|
|||
result['id'] = self.pk
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
def details_display(self, **kwargs):
|
||||
return {
|
||||
'id': self.pk,
|
||||
'display': [
|
||||
|
@ -72,8 +72,8 @@ class TitledMixin(SerializableMixin, models.Model):
|
|||
result['title'] = self.title
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
for lang, title in sorted(self.titles.items(), key=lambda item: item[0] != get_language()):
|
||||
language = _('Title ({lang})').format(lang=get_language_info(lang)['name_translated'])
|
||||
result['display'].append((language, title))
|
||||
|
|
|
@ -2,7 +2,7 @@ import math
|
|||
from collections import OrderedDict
|
||||
|
||||
from django.utils.functional import cached_property
|
||||
from shapely.geometry import Point, mapping
|
||||
from shapely.geometry import Point, box, mapping
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from c3nav.mapdata.models.base import SerializableMixin
|
||||
|
@ -78,9 +78,12 @@ class GeometryMixin(SerializableMixin):
|
|||
(int(math.ceil(maxx)), int(math.ceil(maxy))))
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
result['geometry'] = format_geojson(mapping(self.geometry), round=False)
|
||||
def details_display(self, detailed_geometry=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
if detailed_geometry:
|
||||
result['geometry'] = format_geojson(mapping(self.geometry), round=False)
|
||||
else:
|
||||
result['geometry'] = format_geojson(mapping(box(*self.geometry.bounds)), round=False)
|
||||
return result
|
||||
|
||||
def get_shadow_geojson(self):
|
||||
|
|
|
@ -49,8 +49,8 @@ class LevelGeometryMixin(GeometryMixin):
|
|||
result['level'] = self.level_id
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].insert(3, (
|
||||
_('Level'),
|
||||
{
|
||||
|
@ -126,13 +126,14 @@ class Space(LevelGeometryMixin, SpecificLocation, models.Model):
|
|||
result['height'] = None if self.height is None else float(str(self.height))
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, editor_url=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].extend([
|
||||
(_('height'), self.height),
|
||||
(_('outside only'), _('Yes') if self.outside else _('No')),
|
||||
])
|
||||
result['editor_url'] = reverse('editor.spaces.detail', kwargs={'level': self.level_id, 'pk': self.pk})
|
||||
if editor_url:
|
||||
result['editor_url'] = reverse('editor.spaces.detail', kwargs={'level': self.level_id, 'pk': self.pk})
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
@ -73,8 +73,8 @@ class SpaceGeometryMixin(GeometryMixin):
|
|||
self.geometry if force else self.get_changed_geometry()
|
||||
))
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].insert(3, (
|
||||
_('Space'),
|
||||
{
|
||||
|
@ -125,9 +125,10 @@ class Area(SpaceGeometryMixin, SpecificLocation, models.Model):
|
|||
result = super()._serialize(**kwargs)
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
result['editor_url'] = reverse('editor.areas.edit', kwargs={'space': self.space_id, 'pk': self.pk})
|
||||
def details_display(self, editor_url=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
if editor_url:
|
||||
result['editor_url'] = reverse('editor.areas.edit', kwargs={'space': self.space_id, 'pk': self.pk})
|
||||
return result
|
||||
|
||||
|
||||
|
@ -224,9 +225,10 @@ class POI(SpaceGeometryMixin, SpecificLocation, models.Model):
|
|||
verbose_name_plural = _('Points of Interest')
|
||||
default_related_name = 'pois'
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
result['editor_url'] = reverse('editor.pois.edit', kwargs={'space': self.space_id, 'pk': self.pk})
|
||||
def details_display(self, editor_url=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
if editor_url:
|
||||
result['editor_url'] = reverse('editor.pois.edit', kwargs={'space': self.space_id, 'pk': self.pk})
|
||||
return result
|
||||
|
||||
@property
|
||||
|
|
|
@ -77,14 +77,15 @@ class Level(SpecificLocation, models.Model):
|
|||
result['door_height'] = float(str(self.door_height))
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, editor_url=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].insert(3, (_('short label'), self.short_label))
|
||||
result['display'].extend([
|
||||
(_('outside only'), self.base_altitude),
|
||||
(_('default height'), self.default_height),
|
||||
])
|
||||
result['editor_url'] = reverse('editor.levels.detail', kwargs={'pk': self.pk})
|
||||
if editor_url:
|
||||
result['editor_url'] = reverse('editor.levels.detail', kwargs={'pk': self.pk})
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
|
|
|
@ -60,8 +60,8 @@ class LocationSlug(SerializableMixin, models.Model):
|
|||
result['slug'] = self.get_slug()
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].insert(2, (_('Slug'), str(self.get_slug())))
|
||||
return result
|
||||
|
||||
|
@ -96,8 +96,8 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model):
|
|||
result['can_describe'] = self.can_search
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].extend([
|
||||
(_('searchable'), _('Yes') if self.can_search else _('No')),
|
||||
(_('can describe'), _('Yes') if self.can_describe else _('No'))
|
||||
|
@ -143,8 +143,8 @@ class SpecificLocation(Location, models.Model):
|
|||
result['groups'] = groups
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
|
||||
groupcategories = {}
|
||||
for group in self.groups.all():
|
||||
|
@ -258,14 +258,15 @@ class LocationGroup(Location, models.Model):
|
|||
result['locations'] = tuple(obj.pk for obj in getattr(self, 'locations', ()))
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
result = super().details_display()
|
||||
def details_display(self, editor_url=True, **kwargs):
|
||||
result = super().details_display(**kwargs)
|
||||
result['display'].insert(3, (_('Category'), self.category.title))
|
||||
result['display'].extend([
|
||||
(_('color'), self.color),
|
||||
(_('priority'), self.priority),
|
||||
])
|
||||
result['editor_url'] = reverse('editor.locationgroups.edit', kwargs={'pk': self.pk})
|
||||
if editor_url:
|
||||
result['editor_url'] = reverse('editor.locationgroups.edit', kwargs={'pk': self.pk})
|
||||
return result
|
||||
|
||||
@property
|
||||
|
|
|
@ -294,7 +294,7 @@ class CustomLocation:
|
|||
|
||||
return result
|
||||
|
||||
def details_display(self):
|
||||
def details_display(self, **kwargs):
|
||||
return {
|
||||
'id': self.pk,
|
||||
'display': [
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.conf import settings
|
||||
from django.utils.functional import lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
|
@ -28,3 +29,11 @@ def get_user_data(request):
|
|||
|
||||
|
||||
get_user_data_lazy = lazy(get_user_data, dict)
|
||||
|
||||
|
||||
def can_access_base_mapdata(request):
|
||||
return settings.PUBLIC_BASE_MAPDATA or request.user_permissions.base_mapdata_access
|
||||
|
||||
|
||||
def can_access_editor(request):
|
||||
return settings.PUBLIC_EDITOR or request.user_permissions.editor_access
|
||||
|
|
|
@ -41,6 +41,9 @@ if not os.path.exists(TILES_ROOT):
|
|||
if not os.path.exists(CACHE_ROOT):
|
||||
os.mkdir(CACHE_ROOT)
|
||||
|
||||
PUBLIC_EDITOR = config.get('c3nav', 'editor', fallback=True)
|
||||
PUBLIC_BASE_MAPDATA = config.get('c3nav', 'public_base_mapdata', fallback=False)
|
||||
|
||||
if config.has_option('django', 'secret'):
|
||||
SECRET_KEY = config.get('django', 'secret')
|
||||
else:
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
{% get_current_language as CURRENT_LANGUAGE %}
|
||||
<a href="{% url 'site.language' %}" id="choose-language">{{ CURRENT_LANGUAGE | language_name_local }}</a> –
|
||||
{% endif %}
|
||||
<a href="{% url 'editor.index' %}" target="_blank">{% trans 'Editor' %}</a> //
|
||||
{% if editor %}
|
||||
<a href="{% url 'editor.index' %}" target="_blank">{% trans 'Editor' %}</a> //
|
||||
{% endif %}
|
||||
<a href="/api/" target="_blank">{% trans 'API' %}</a> //
|
||||
<a href="https://twitter.com/c3nav/" rel="external" target="_blank">Twitter</a> //
|
||||
<a href="https://github.com/c3nav/c3nav/" rel="external" target="_blank">GitHub</a>
|
||||
|
|
|
@ -26,7 +26,7 @@ from c3nav.mapdata.models import Location, Source
|
|||
from c3nav.mapdata.models.access import AccessPermissionToken
|
||||
from c3nav.mapdata.models.locations import LocationRedirect, SpecificLocation
|
||||
from c3nav.mapdata.utils.locations import get_location_by_slug_for_request, levels_by_short_label_for_request
|
||||
from c3nav.mapdata.utils.user import get_user_data
|
||||
from c3nav.mapdata.utils.user import can_access_editor, get_user_data
|
||||
from c3nav.mapdata.views import set_tile_access_cookie
|
||||
from c3nav.site.models import Announcement, SiteUpdate
|
||||
|
||||
|
@ -123,6 +123,7 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N
|
|||
'initial_bounds': json.dumps(initial_bounds, separators=(',', ':')) if initial_bounds else None,
|
||||
'last_site_update': json.dumps(SiteUpdate.last_update()),
|
||||
'ssids': json.dumps(settings.WIFI_SSIDS, separators=(',', ':')) if settings.WIFI_SSIDS else None,
|
||||
'editor': can_access_editor(request),
|
||||
'embed': bool(embed),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue