2016-12-19 23:58:12 +01:00
|
|
|
from datetime import timedelta
|
2016-12-15 17:30:55 +01:00
|
|
|
|
2016-12-22 02:40:12 +01:00
|
|
|
import qrcode
|
2016-12-21 20:56:28 +01:00
|
|
|
from django.core.files import File
|
2017-01-13 21:52:44 +01:00
|
|
|
from django.http import Http404, HttpResponse, HttpResponseNotModified, JsonResponse
|
2016-12-20 22:20:42 +01:00
|
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
2016-12-20 20:29:18 +01:00
|
|
|
from django.urls import reverse
|
2016-12-19 23:58:12 +01:00
|
|
|
from django.utils import timezone
|
2016-12-17 19:25:27 +01:00
|
|
|
|
2016-12-21 20:56:28 +01:00
|
|
|
from c3nav.access.apply import get_visible_areas
|
2016-12-21 13:31:56 +01:00
|
|
|
from c3nav.mapdata.inclusion import get_includables_avoidables, parse_include_avoid
|
2016-12-21 21:28:31 +01:00
|
|
|
from c3nav.mapdata.lastupdate import get_last_mapdata_update
|
2016-12-17 19:25:27 +01:00
|
|
|
from c3nav.mapdata.models import Level
|
2016-12-21 20:56:28 +01:00
|
|
|
from c3nav.mapdata.search import get_location, search_location
|
2016-12-20 22:20:42 +01:00
|
|
|
from c3nav.mapdata.utils.cache import get_levels_cached
|
2016-12-21 20:56:28 +01:00
|
|
|
from c3nav.mapdata.utils.misc import get_dimensions, get_render_path
|
2016-12-21 11:55:04 +01:00
|
|
|
from c3nav.routing.exceptions import AlreadyThere, NoRouteFound, NotYetRoutable
|
2016-12-16 17:38:13 +01:00
|
|
|
from c3nav.routing.graph import Graph
|
2016-12-15 17:30:55 +01:00
|
|
|
|
2016-12-19 01:31:20 +01:00
|
|
|
ctype_mapping = {
|
|
|
|
'yes': ('up', 'down'),
|
|
|
|
'up': ('up', ),
|
|
|
|
'down': ('down', ),
|
|
|
|
'no': ()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def get_ctypes(prefix, value):
|
2016-12-19 12:24:07 +01:00
|
|
|
return tuple((prefix+'_'+direction) for direction in ctype_mapping.get(value, ('up', 'down')))
|
2016-12-15 17:30:55 +01:00
|
|
|
|
2016-12-15 18:28:04 +01:00
|
|
|
|
2016-12-19 23:58:12 +01:00
|
|
|
def reverse_ctypes(ctypes, name):
|
|
|
|
if name+'_up' in ctypes:
|
|
|
|
return 'yes' if name + '_down' in ctypes else 'up'
|
|
|
|
else:
|
|
|
|
return 'down' if name + '_down' in ctypes else 'no'
|
|
|
|
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
def get_location_or_404(request, location):
|
|
|
|
if location is None:
|
|
|
|
return None
|
2016-12-15 18:28:04 +01:00
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
location = get_location(request, location)
|
|
|
|
if location is None:
|
|
|
|
raise Http404
|
2016-12-15 18:28:04 +01:00
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
return location
|
|
|
|
|
|
|
|
|
2016-12-22 02:40:12 +01:00
|
|
|
def qr_code(request, location):
|
|
|
|
location = get_location_or_404(request, location)
|
|
|
|
|
|
|
|
qr = qrcode.QRCode(
|
|
|
|
version=1,
|
|
|
|
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
|
|
|
box_size=10,
|
|
|
|
border=4,
|
|
|
|
)
|
|
|
|
qr.add_data(request.build_absolute_uri(reverse('site.location', kwargs={'location': location.location_id})))
|
|
|
|
qr.make(fit=True)
|
|
|
|
|
|
|
|
response = HttpResponse(content_type='image/png')
|
|
|
|
qr.make_image().save(response, 'PNG')
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
def main(request, location=None, origin=None, destination=None):
|
|
|
|
location = get_location_or_404(request, location)
|
|
|
|
origin = get_location_or_404(request, origin)
|
|
|
|
destination = get_location_or_404(request, destination)
|
|
|
|
|
|
|
|
mode = 'location' if not origin and not destination else 'route'
|
|
|
|
|
2016-12-20 22:20:42 +01:00
|
|
|
active_field = None
|
|
|
|
if not origin and not destination:
|
|
|
|
active_field = 'location'
|
|
|
|
elif origin and not destination:
|
|
|
|
active_field = 'destination'
|
|
|
|
elif destination and not origin:
|
|
|
|
active_field = 'origin'
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
ctx = {
|
|
|
|
'location': location,
|
|
|
|
'origin': origin,
|
|
|
|
'destination': destination,
|
|
|
|
'mode': mode,
|
2016-12-20 22:20:42 +01:00
|
|
|
'active_field': active_field,
|
2016-12-21 20:14:40 +01:00
|
|
|
|
|
|
|
'full_access': request.c3nav_full_access,
|
|
|
|
'access_list': request.c3nav_access_list,
|
2016-12-21 20:56:28 +01:00
|
|
|
'visible_areas': get_visible_areas(request),
|
2016-12-20 20:29:18 +01:00
|
|
|
}
|
|
|
|
|
2016-12-20 22:20:42 +01:00
|
|
|
width, height = get_dimensions()
|
|
|
|
levels = tuple(name for name, level in get_levels_cached().items() if not level.intermediate)
|
2016-12-20 20:29:18 +01:00
|
|
|
|
2016-12-20 22:20:42 +01:00
|
|
|
ctx.update({
|
|
|
|
'width': width,
|
|
|
|
'height': height,
|
|
|
|
'svg_width': int(width * 6),
|
|
|
|
'svg_height': int(height * 6),
|
|
|
|
'levels': levels,
|
|
|
|
})
|
|
|
|
|
|
|
|
map_level = request.GET.get('map-level')
|
|
|
|
if map_level in levels:
|
|
|
|
ctx.update({
|
|
|
|
'map_level': map_level
|
|
|
|
})
|
|
|
|
|
|
|
|
if 'x' in request.POST and 'y' in request.POST:
|
|
|
|
x = request.POST.get('x')
|
|
|
|
y = request.POST.get('y')
|
|
|
|
if x.isnumeric() and y.isnumeric():
|
2016-12-21 00:24:56 +01:00
|
|
|
coords = 'c:%s:%d:%d' % (map_level, int(int(x)/6*100), height-int(int(y)/6*100))
|
2016-12-20 22:20:42 +01:00
|
|
|
if active_field == 'origin':
|
|
|
|
return redirect('site.route', origin=coords, destination=destination.location_id)
|
|
|
|
elif active_field == 'destination':
|
|
|
|
return redirect('site.route', origin=origin.location_id, destination=coords)
|
|
|
|
elif active_field == 'location':
|
|
|
|
return redirect('site.location', location=coords)
|
|
|
|
|
|
|
|
if active_field is not None:
|
|
|
|
search_query = request.POST.get(active_field+'_search', '').strip() or None
|
2016-12-20 20:29:18 +01:00
|
|
|
if search_query:
|
|
|
|
results = search_location(request, search_query)
|
|
|
|
|
2016-12-20 22:20:42 +01:00
|
|
|
url = 'site.location' if active_field == 'location' else 'site.route'
|
2016-12-20 20:29:18 +01:00
|
|
|
kwargs = {}
|
|
|
|
if origin:
|
|
|
|
kwargs['origin'] = origin.location_id
|
|
|
|
if destination:
|
|
|
|
kwargs['destination'] = destination.location_id
|
|
|
|
for result in results:
|
2016-12-20 22:20:42 +01:00
|
|
|
kwargs[active_field] = result.location_id
|
2016-12-20 20:29:18 +01:00
|
|
|
result.url = reverse(url, kwargs=kwargs)
|
|
|
|
|
|
|
|
ctx.update({
|
2016-12-20 22:20:42 +01:00
|
|
|
'search': active_field,
|
2016-12-20 20:29:18 +01:00
|
|
|
'search_query': search_query,
|
|
|
|
'search_results': results,
|
|
|
|
})
|
|
|
|
|
|
|
|
# everything about settings
|
2016-12-19 23:58:12 +01:00
|
|
|
include = ()
|
|
|
|
avoid = ()
|
|
|
|
stairs = 'yes'
|
|
|
|
escalators = 'yes'
|
|
|
|
elevators = 'yes'
|
2016-12-19 22:52:09 +01:00
|
|
|
|
2016-12-19 23:58:12 +01:00
|
|
|
save_settings = False
|
|
|
|
if 'c3nav_settings' in request.COOKIES:
|
|
|
|
cookie_value = request.COOKIES['c3nav_settings']
|
2016-12-19 01:31:20 +01:00
|
|
|
|
2016-12-19 23:58:12 +01:00
|
|
|
if isinstance(cookie_value, dict):
|
|
|
|
stairs = cookie_value.get('stairs', stairs)
|
|
|
|
escalators = cookie_value.get('escalators', escalators)
|
|
|
|
elevators = cookie_value.get('elevators', elevators)
|
|
|
|
|
|
|
|
if isinstance(cookie_value.get('include'), list):
|
|
|
|
include = cookie_value.get('include')
|
|
|
|
|
|
|
|
if isinstance(cookie_value.get('avoid'), list):
|
|
|
|
avoid = cookie_value.get('avoid')
|
|
|
|
|
|
|
|
save_settings = True
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
if request.method == 'POST':
|
2016-12-19 23:58:12 +01:00
|
|
|
stairs = request.POST.get('stairs', stairs)
|
|
|
|
escalators = request.POST.get('escalators', escalators)
|
|
|
|
elevators = request.POST.get('elevators', elevators)
|
2016-12-19 01:31:20 +01:00
|
|
|
|
2016-12-19 22:52:09 +01:00
|
|
|
include = request.POST.getlist('include')
|
|
|
|
avoid = request.POST.getlist('avoid')
|
|
|
|
|
2016-12-19 23:58:12 +01:00
|
|
|
allowed_ctypes = ('', )
|
|
|
|
allowed_ctypes += get_ctypes('stairs', request.POST.get('stairs', stairs))
|
|
|
|
allowed_ctypes += get_ctypes('escalator', request.POST.get('escalators', escalators))
|
|
|
|
allowed_ctypes += get_ctypes('elevator', request.POST.get('elevators', elevators))
|
|
|
|
|
|
|
|
stairs = reverse_ctypes(allowed_ctypes, 'stairs')
|
|
|
|
escalators = reverse_ctypes(allowed_ctypes, 'escalator')
|
|
|
|
elevators = reverse_ctypes(allowed_ctypes, 'elevator')
|
2016-12-19 22:52:09 +01:00
|
|
|
|
2016-12-21 13:31:56 +01:00
|
|
|
includables, avoidables = get_includables_avoidables(request)
|
|
|
|
allow_nonpublic, include, avoid = parse_include_avoid(request, include, avoid)
|
2016-12-19 23:58:12 +01:00
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
if request.method == 'POST':
|
2016-12-19 23:58:12 +01:00
|
|
|
save_settings = request.POST.get('save_settings', '') == '1'
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
ctx.update({
|
|
|
|
'stairs': stairs,
|
|
|
|
'escalators': escalators,
|
|
|
|
'elevators': elevators,
|
2016-12-21 13:31:56 +01:00
|
|
|
'excludables': avoidables.items(),
|
2016-12-20 20:29:18 +01:00
|
|
|
'includables': includables.items(),
|
|
|
|
'include': include,
|
|
|
|
'avoid': avoid,
|
|
|
|
'save_settings': save_settings,
|
|
|
|
})
|
|
|
|
|
|
|
|
# routing
|
|
|
|
if request.method == 'POST' and origin and destination:
|
2016-12-19 23:58:12 +01:00
|
|
|
graph = Graph.load()
|
2016-12-17 19:25:27 +01:00
|
|
|
|
2016-12-21 01:59:08 +01:00
|
|
|
try:
|
2016-12-21 13:31:56 +01:00
|
|
|
route = graph.get_route(origin, destination, allowed_ctypes, allow_nonpublic=allow_nonpublic,
|
2016-12-21 01:59:08 +01:00
|
|
|
avoid=avoid-set(':public'), include=include-set(':nonpublic'))
|
|
|
|
except NoRouteFound:
|
|
|
|
ctx.update({'error': 'noroutefound'})
|
|
|
|
except AlreadyThere:
|
|
|
|
ctx.update({'error': 'alreadythere'})
|
2016-12-21 11:55:04 +01:00
|
|
|
except NotYetRoutable:
|
|
|
|
ctx.update({'error': 'notyetroutable'})
|
2016-12-21 01:59:08 +01:00
|
|
|
else:
|
2016-12-24 01:41:32 +01:00
|
|
|
route.describe(allowed_ctypes)
|
2016-12-21 01:59:08 +01:00
|
|
|
ctx.update({'route': route})
|
2016-12-19 22:52:09 +01:00
|
|
|
|
2016-12-29 20:06:57 +01:00
|
|
|
if request.GET.get('format') == 'json':
|
|
|
|
if 'error' in ctx:
|
|
|
|
return JsonResponse({'error': ctx['error']})
|
|
|
|
if 'route' in ctx:
|
|
|
|
return JsonResponse({'route': ctx['route'].serialize()})
|
|
|
|
|
2016-12-20 20:29:18 +01:00
|
|
|
response = render(request, 'site/main.html', ctx)
|
|
|
|
|
|
|
|
if request.method == 'POST' and save_settings:
|
2016-12-19 23:58:12 +01:00
|
|
|
cookie_value = {
|
|
|
|
'stairs': stairs,
|
|
|
|
'escalators': escalators,
|
|
|
|
'elevators': elevators,
|
|
|
|
'include': tuple(include),
|
|
|
|
'avoid': tuple(avoid),
|
|
|
|
}
|
|
|
|
response.set_cookie('c3nav_settings', cookie_value, expires=timezone.now() + timedelta(days=30))
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
2016-12-17 19:25:27 +01:00
|
|
|
|
2016-12-21 21:28:31 +01:00
|
|
|
def map_image(request, area, level):
|
2016-12-17 19:25:27 +01:00
|
|
|
level = get_object_or_404(Level, name=level, intermediate=False)
|
2016-12-21 20:56:28 +01:00
|
|
|
if area == ':base':
|
|
|
|
img = get_render_path('png', level.name, 'full', True)
|
|
|
|
elif area == ':full':
|
|
|
|
if not request.c3nav_full_access:
|
|
|
|
raise Http404
|
|
|
|
img = get_render_path('png', level.name, 'full', False)
|
2016-12-21 22:23:42 +01:00
|
|
|
elif area in request.c3nav_access_list:
|
|
|
|
img = get_render_path(area+'.png', level.name, 'full', False)
|
2016-12-21 20:56:28 +01:00
|
|
|
else:
|
|
|
|
raise Http404
|
|
|
|
|
2016-12-21 21:28:31 +01:00
|
|
|
last_update = get_last_mapdata_update()
|
2016-12-22 12:12:06 +01:00
|
|
|
etag = '-'.join(str(i) for i in last_update.timetuple())
|
2016-12-21 21:28:31 +01:00
|
|
|
|
2016-12-22 12:12:06 +01:00
|
|
|
if_none_match = request.META.get('HTTP_IF_NONE_MATCH')
|
|
|
|
if if_none_match:
|
2016-12-22 14:22:29 +01:00
|
|
|
if if_none_match == etag:
|
2016-12-21 21:28:31 +01:00
|
|
|
return HttpResponseNotModified()
|
|
|
|
|
2016-12-22 02:31:48 +01:00
|
|
|
response = HttpResponse(content_type='image/png')
|
2016-12-21 20:56:28 +01:00
|
|
|
for chunk in File(open(img, 'rb')).chunks():
|
|
|
|
response.write(chunk)
|
2016-12-21 21:28:31 +01:00
|
|
|
|
2016-12-22 12:28:13 +01:00
|
|
|
response['ETag'] = etag
|
|
|
|
response['Cache-Control'] = 'no-cache'
|
2016-12-21 20:56:28 +01:00
|
|
|
return response
|