dynamic location as a starting point

This commit is contained in:
Laura Klünder 2019-12-27 23:27:50 +01:00
parent cca263c605
commit 1ecdc89a68
7 changed files with 63 additions and 13 deletions

View file

@ -470,6 +470,22 @@ class CustomLocationProxyMixin:
def get_custom_location(self):
raise NotImplementedError
@property
def available(self):
return self.get_custom_location() is not None
@property
def x(self):
return self.get_custom_location().x
@property
def y(self):
return self.get_custom_location().y
@property
def level(self):
return self.get_custom_location().level
def serialize_position(self):
raise NotImplementedError
@ -550,6 +566,9 @@ class Position(CustomLocationProxyMixin, models.Model):
coordinates_id = models.CharField(_('coordinates'), null=True, max_length=48)
api_secret = models.CharField(_('api secret'), max_length=64, default=get_position_api_secret)
can_search = True
can_describe = False
coordinates = LocationById()
class Meta:
@ -583,8 +602,8 @@ class Position(CustomLocationProxyMixin, models.Model):
custom_location = self.get_custom_location()
if custom_location is None:
return {
'id': self.secret,
'slug': self.secret,
'id': 'p:%s' % self.secret,
'slug': 'p:%s' % self.secret,
'available': False,
'icon': 'my_location',
'title': self.name,
@ -606,6 +625,18 @@ class Position(CustomLocationProxyMixin, models.Model):
})
return result
@property
def slug(self):
return 'p:%s' % self.secret
def serialize(self, *args, **kwargs):
return self.serialize_position()
def get_geometry(self, *args, **kwargs):
return None
level_id = None
def save(self, *args, **kwargs):
with transaction.atomic():
super().save(*args, **kwargs)

View file

@ -4,7 +4,7 @@ import re
from collections import OrderedDict
from functools import reduce
from itertools import chain
from typing import List, Mapping, Optional
from typing import List, Mapping, Optional, Union
from django.apps import apps
from django.db.models import Prefetch, Q
@ -18,7 +18,7 @@ from c3nav.mapdata.models.access import AccessPermission
from c3nav.mapdata.models.geometry.base import GeometryMixin
from c3nav.mapdata.models.geometry.level import LevelGeometryMixin, Space
from c3nav.mapdata.models.geometry.space import SpaceGeometryMixin
from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug, SpecificLocation
from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug, Position, SpecificLocation
from c3nav.mapdata.utils.cache.local import LocalCacheProxy
from c3nav.mapdata.utils.models import get_submodels
@ -206,12 +206,18 @@ def get_location_by_id_for_request(pk, request):
if isinstance(pk, str):
if pk.isdigit():
pk = int(pk)
elif pk.startswith('p:'):
try:
# return immediately, don't cache for obvious reasons
return Position.objects.get(secret=pk[2:])
except Position.DoesNotExist:
return None
else:
return get_custom_location_for_request(pk, request)
return locations_for_request(request).get(pk)
def get_location_by_slug_for_request(slug: str, request) -> Optional[LocationSlug]:
def get_location_by_slug_for_request(slug: str, request) -> Optional[Union[LocationSlug, Position]]:
cache_key = 'mapdata:location:by_slug:%s:%s' % (AccessPermission.cache_key_for_request(request), slug)
location = proxied_cache.get(cache_key, None)
if location is not None:
@ -221,6 +227,12 @@ def get_location_by_slug_for_request(slug: str, request) -> Optional[LocationSlu
location = get_custom_location_for_request(slug, request)
if location is None:
return None
elif slug.startswith('p:'):
try:
# return immediately, don't cache for obvious reasons
return Position.objects.get(secret=slug[2:])
except Position.DoesNotExist:
return None
elif ':' in slug:
code, pk = slug.split(':', 1)
model_name = LocationSlug.LOCATION_TYPE_BY_CODE.get(code)

View file

@ -7,6 +7,7 @@ from rest_framework.viewsets import ViewSet
from c3nav.mapdata.api import api_stats_clean_location_value
from c3nav.mapdata.models.access import AccessPermission
from c3nav.mapdata.models.locations import Position
from c3nav.mapdata.utils.cache.stats import increment_cache_key
from c3nav.mapdata.utils.locations import visible_locations_for_request
from c3nav.routing.exceptions import LocationUnreachable, NoRouteFound, NotYetRoutable
@ -71,8 +72,8 @@ class RoutingViewSet(ViewSet):
return Response({
'request': {
'origin': form.cleaned_data['origin'].pk,
'destination': form.cleaned_data['destination'].pk,
'origin': self.get_request_pk(form.cleaned_data['origin']),
'destination': self.get_request_pk(form.cleaned_data['destination']),
},
'options': options.serialize(),
'report_issue_url': reverse('site.report_create', kwargs={
@ -83,6 +84,9 @@ class RoutingViewSet(ViewSet):
'result': route.serialize(locations=visible_locations_for_request(request)),
})
def get_request_pk(self, location):
return location.slug if isinstance(location, Position) else location.pk
@action(detail=False, methods=['get', 'post'])
def options(self, request, *args, **kwargs):
options = RouteOptions.get_for_request(request)

View file

@ -12,7 +12,10 @@ def describe_location(location, locations):
final_location = locations.get(location.pk)
if final_location is not None:
location = final_location
return location.serialize(include_type=True, detailed=False, simple_geometry=True)
result = location.serialize(include_type=True, detailed=False, simple_geometry=True)
if hasattr(location, 'serialize_position'):
result.update(location.serialize_position())
return result
class Route:
@ -170,7 +173,6 @@ class Route:
options_summary = ', '.join(str(s) for s in options_summary)
return OrderedDict((
('origin', describe_location(self.origin, locations)),
('destination', describe_location(self.destination, locations)),

View file

@ -328,8 +328,8 @@ class Router:
if poi.space_id not in restrictions.spaces and poi.access_restriction_id not in restrictions),
))
elif isinstance(location, (CustomLocation, CustomLocationProxyMixin)):
if isinstance(location, CustomLocationProxyMixin):
location = location.get_custom_location()
if isinstance(location, CustomLocationProxyMixin) and not location.available:
raise LocationUnreachable
point = Point(location.x, location.y)
location = RouterPoint(location)
space = self.space_for_point(location.level.pk, point, restrictions)

View file

@ -1547,6 +1547,7 @@ c3nav = {
$.getJSON('/api/locations/' + location.id + '/geometry/', c3nav._location_geometry_loaded);
}
if (!location.point) return;
var point = c3nav._location_point_overrides[location.id] || location.point.slice(1),
latlng = L.GeoJSON.coordsToLatLng(point),
buttons = $('#location-popup-buttons').clone();

View file

@ -4,9 +4,9 @@ from c3nav.site.views import (about_view, access_redeem_view, account_view, chan
login_view, logout_view, map_index, position_create, position_detail, position_list,
position_set, qr_code, register_view, report_create, report_detail, report_list)
slug = r'(?P<slug>[a-z0-9-_.:]+)'
slug = r'(?P<slug>[a-zA-Z0-9-_.:]+)'
coordinates = r'(?P<coordinates>[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)'
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
slug2 = r'(?P<slug2>[a-zA-Z0-9-_.:]+)'
details = r'(?P<details>details/)?'
nearby = r'(?P<nearby>nearby/)?'
options = r'(?P<options>options/)?'