add api to retrieve locations
This commit is contained in:
parent
d6d025ce97
commit
feb8848fe0
3 changed files with 160 additions and 3 deletions
|
@ -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')
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
129
src/c3nav/mapdata/locations.py
Normal file
129
src/c3nav/mapdata/locations.py
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue