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 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.register(r'packages', PackageViewSet)
|
||||
|
@ -18,6 +19,8 @@ router.register(r'sources', SourceViewSet)
|
|||
router.register(r'geometrytypes', GeometryTypeViewSet, base_name='geometrytype')
|
||||
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'submittasks', SubmitTaskViewSet, base_name='submittask')
|
||||
|
||||
|
|
|
@ -4,12 +4,13 @@ from collections import OrderedDict
|
|||
|
||||
from django.conf import settings
|
||||
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.response import Response
|
||||
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.permissions import filter_queryset_by_package_access, get_unlocked_packages_names
|
||||
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():
|
||||
response.write(chunk)
|
||||
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