team-3/src/c3nav/routing/api.py

106 lines
4.2 KiB
Python
Raw Normal View History

2017-12-16 19:33:13 +01:00
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from rest_framework.decorators import action
2017-11-27 16:40:15 +01:00
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
2018-12-25 18:43:24 +01:00
from c3nav.mapdata.api import api_stats_clean_location_value
2017-11-28 00:41:34 +01:00
from c3nav.mapdata.models.access import AccessPermission
2018-12-25 18:43:24 +01:00
from c3nav.mapdata.utils.cache.stats import increment_cache_key
2017-12-26 00:16:43 +01:00
from c3nav.mapdata.utils.locations import visible_locations_for_request
from c3nav.routing.exceptions import LocationUnreachable, NoRouteFound, NotYetRoutable
2017-11-27 16:40:15 +01:00
from c3nav.routing.forms import RouteForm
from c3nav.routing.locator import Locator
2017-12-12 23:09:15 +01:00
from c3nav.routing.models import RouteOptions
2017-11-27 16:40:15 +01:00
from c3nav.routing.router import Router
class RoutingViewSet(ViewSet):
2017-12-16 19:33:13 +01:00
"""
/route/ Get routes.
/options/ Get or set route options.
/locate/ Wifi locate.
2017-12-16 19:33:13 +01:00
"""
@action(detail=False, methods=['get', 'post'])
2017-11-27 16:40:15 +01:00
def route(self, request, *args, **kwargs):
params = request.POST if request.method == 'POST' else request.GET
form = RouteForm(params, request=request)
if not form.is_valid():
return Response({
'errors': form.errors,
2017-12-16 19:33:13 +01:00
}, status=400)
options = RouteOptions.get_for_request(request)
try:
options.update(params, ignore_unknown=True)
except ValidationError as e:
return Response({
'errors': (str(e), ),
}, status=400)
2017-11-27 16:40:15 +01:00
try:
route = Router.load().get_route(origin=form.cleaned_data['origin'],
destination=form.cleaned_data['destination'],
2017-12-16 22:14:00 +01:00
permissions=AccessPermission.get_for_request(request),
options=options)
except NotYetRoutable:
return Response({
'error': _('Not yet routable, try again shortly.'),
})
except LocationUnreachable:
return Response({
'error': _('Unreachable location.'),
})
except NoRouteFound:
return Response({
'error': _('No route found.'),
})
2017-11-27 16:40:15 +01:00
2018-12-25 19:31:24 +01:00
origin_values = api_stats_clean_location_value(form.cleaned_data['origin'].pk)
destination_values = api_stats_clean_location_value(form.cleaned_data['destination'].pk)
increment_cache_key('apistats__route')
for origin_value in origin_values:
for destination_value in destination_values:
increment_cache_key('apistats__route_tuple_%s_%s' % (origin_value, destination_value))
for value in origin_values:
increment_cache_key('apistats__route_origin_%s' % value)
for value in destination_values:
increment_cache_key('apistats__route_destination_%s' % value)
2018-12-25 18:43:24 +01:00
2017-11-28 12:32:46 +01:00
return Response({
'request': {
'origin': form.cleaned_data['origin'].pk,
'destination': form.cleaned_data['destination'].pk,
},
2017-12-16 19:33:13 +01:00
'options': options.serialize(),
2017-11-28 12:32:46 +01:00
'result': route.serialize(locations=visible_locations_for_request(request)),
})
2017-12-12 23:09:15 +01:00
@action(detail=False, methods=['get', 'post'])
2017-12-12 23:09:15 +01:00
def options(self, request, *args, **kwargs):
2017-12-16 21:22:43 +01:00
options = RouteOptions.get_for_request(request)
2017-12-12 23:09:15 +01:00
2017-12-16 21:22:43 +01:00
if request.method == 'POST':
try:
options.update(request.POST, ignore_unknown=True)
except ValidationError as e:
return Response({
'errors': (str(e),),
}, status=400)
options.save()
2017-12-12 23:09:15 +01:00
2017-12-16 19:33:13 +01:00
return Response(options.serialize())
@action(detail=False, methods=('POST', ))
def locate(self, request, *args, **kwargs):
try:
2017-12-26 00:16:43 +01:00
location = Locator.load().locate(request.data, permissions=AccessPermission.get_for_request(request))
2018-12-25 19:32:41 +01:00
increment_cache_key('apistats__locate__%s' % location.pk)
except ValidationError:
return Response({
'errors': (_('Invalid scan data.'),),
}, status=400)
return Response({'location': None if location is None else location.serialize(simple_geometry=True)})