add api to retrieve locations

This commit is contained in:
Laura Klünder 2016-12-15 13:18:46 +01:00
parent d6d025ce97
commit feb8848fe0
3 changed files with 160 additions and 3 deletions

View file

@ -8,7 +8,8 @@ from rest_framework.response import Response
from rest_framework.routers import SimpleRouter from rest_framework.routers import SimpleRouter
from c3nav.editor.api import HosterViewSet, SubmitTaskViewSet from c3nav.editor.api import HosterViewSet, SubmitTaskViewSet
from c3nav.mapdata.api import GeometryTypeViewSet, GeometryViewSet, LevelViewSet, PackageViewSet, SourceViewSet from c3nav.mapdata.api import (GeometryTypeViewSet, GeometryViewSet, LevelViewSet, LocationViewSet, PackageViewSet,
SourceViewSet)
router = SimpleRouter() router = SimpleRouter()
router.register(r'packages', PackageViewSet) router.register(r'packages', PackageViewSet)
@ -18,6 +19,8 @@ router.register(r'sources', SourceViewSet)
router.register(r'geometrytypes', GeometryTypeViewSet, base_name='geometrytype') router.register(r'geometrytypes', GeometryTypeViewSet, base_name='geometrytype')
router.register(r'geometries', GeometryViewSet, base_name='geometry') router.register(r'geometries', GeometryViewSet, base_name='geometry')
router.register(r'locations', LocationViewSet, base_name='location')
router.register(r'hosters', HosterViewSet, base_name='hoster') router.register(r'hosters', HosterViewSet, base_name='hoster')
router.register(r'submittasks', SubmitTaskViewSet, base_name='submittask') router.register(r'submittasks', SubmitTaskViewSet, base_name='submittask')

View file

@ -4,12 +4,13 @@ from collections import OrderedDict
from django.conf import settings from django.conf import settings
from django.core.files import File from django.core.files import File
from django.http import HttpResponse from django.http import Http404, HttpResponse
from rest_framework.decorators import detail_route from rest_framework.decorators import detail_route
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
from c3nav.mapdata.models import GEOMETRY_MAPITEM_TYPES, Level, Package, Source from c3nav.mapdata.locations import AreaOfInterestLocation, GroupOfInterestLocation, get_location
from c3nav.mapdata.models import GEOMETRY_MAPITEM_TYPES, AreaOfInterest, GroupOfInterest, Level, Package, Source
from c3nav.mapdata.models.geometry import DirectedLineGeometryMapItemWithLevel from c3nav.mapdata.models.geometry import DirectedLineGeometryMapItemWithLevel
from c3nav.mapdata.permissions import filter_queryset_by_package_access, get_unlocked_packages_names from c3nav.mapdata.permissions import filter_queryset_by_package_access, get_unlocked_packages_names
from c3nav.mapdata.serializers.main import LevelSerializer, PackageSerializer, SourceSerializer from c3nav.mapdata.serializers.main import LevelSerializer, PackageSerializer, SourceSerializer
@ -149,3 +150,27 @@ class SourceViewSet(CachedReadOnlyViewSetMixin, ReadOnlyModelViewSet):
for chunk in File(open(image_path, 'rb')).chunks(): for chunk in File(open(image_path, 'rb')).chunks():
response.write(chunk) response.write(chunk)
return response return response
class LocationViewSet(CachedReadOnlyViewSetMixin, ViewSet):
"""
List and retrieve locations
"""
lookup_field = 'name'
include_package_access = True
def list(self, request, **kwargs):
locations = []
for area in filter_queryset_by_package_access(request, AreaOfInterest.objects.all()):
locations.append(AreaOfInterestLocation.from_cache(area))
for group in filter_queryset_by_package_access(request, GroupOfInterest.objects.all()):
locations.append(GroupOfInterestLocation.from_cache(group))
return Response([location.to_json() for location in locations])
def retrieve(self, request, name=None, **kwargs):
location = get_location(request, name)
if location is None:
raise Http404
return Response(location.to_json())

View file

@ -0,0 +1,129 @@
import re
from abc import ABC, abstractmethod
from collections import OrderedDict
from django.core.cache import cache
from c3nav.mapdata.lastupdate import get_last_mapdata_update
from c3nav.mapdata.models import AreaOfInterest, GroupOfInterest, Level
from c3nav.mapdata.permissions import filter_queryset_by_package_access
from c3nav.mapdata.utils.cache import get_levels_cached
def get_location(request, name):
match = re.match('^c:(?P<level>[a-z0-9-_]+):(?P<x>[0-9]+):(?P<y>[0-9]+)$', name)
if match:
levels = get_levels_cached()
level = levels.get(match.group('level'))
if level is None:
return None
return PointLocation.from_cache(level=level, x=int(match.group('x')), y=int(match.group('y')))
if name.startswith('g:'):
group = filter_queryset_by_package_access(request, GroupOfInterest.objects.filter(name=name[2:])).first()
if group is None:
return None
return GroupOfInterestLocation(group)
area = filter_queryset_by_package_access(request, AreaOfInterest.objects.filter(name=name)).first()
if area is None:
return None
return AreaOfInterestLocation(area)
class Location(ABC):
@classmethod
def _from_cache(cls, cache_key, *args, **kwargs):
last_update = get_last_mapdata_update()
if last_update is None:
return cls(*args, **kwargs)
cache_key = 'c3nav__locations__%s__%s__%s' % (last_update.isoformat(), cls.__name__, cache_key)
obj = cache.get(cache_key)
if not obj:
obj = cls(*args, **kwargs)
cache.set(cache_key, obj, 300)
return obj
def __init__(self, name):
self.name = name
@property
@abstractmethod
def title(self) -> str:
pass
@property
@abstractmethod
def subtitle(self) -> str:
pass
def to_json(self):
return OrderedDict((
('name', self.name),
('title', self.title),
('subtitle', self.subtitle),
))
class AreaOfInterestLocation(Location):
@classmethod
def from_cache(cls, area: AreaOfInterest):
return cls._from_cache(area.name, area)
def __init__(self, area: AreaOfInterest):
super().__init__(name=area.name)
self.area = area
@property
def title(self) -> str:
return self.area.title
@property
def subtitle(self) -> str:
return 'Location Group'
class GroupOfInterestLocation(Location):
@classmethod
def from_cache(cls, group: GroupOfInterest):
return cls._from_cache(group.name, group)
def __init__(self, group: GroupOfInterest):
super().__init__(name=group.name)
self.group = group
@property
def title(self) -> str:
return self.group.title
@property
def subtitle(self) -> str:
return 'Location'
class PointLocation(Location):
@classmethod
def from_cache(cls, level: Level, x: int, y: int):
return cls._from_cache('%s:%d:%d' % (level.name, x, y), level, x, y)
def __init__(self, level: Level, x: int, y: int):
super().__init__(name='c:%s:%d:%d' % (level.name, x, y))
self.level = level
self.x = x
self.y = y
@property
def title(self) -> str:
return 'Custom location'
@property
def subtitle(self) -> str:
return 'Coordinates'
def to_json(self):
result = super().to_json()
result['level'] = self.level.name
result['x'] = self.x
result['y'] = self.y
return result