team-3/src/c3nav/site/views.py

317 lines
10 KiB
Python
Raw Normal View History

# flake8: noqa
import json
from collections import OrderedDict
2016-12-19 23:58:12 +01:00
from datetime import timedelta
from typing import Mapping, Optional
2016-12-15 17:30:55 +01:00
2016-12-22 02:40:12 +01:00
import qrcode
from django.core.cache import cache
from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import redirect, render
from django.urls import reverse
2016-12-19 23:58:12 +01:00
from django.utils import timezone
from c3nav.mapdata.models import Location, Source
from c3nav.mapdata.models.access import AccessPermission
2017-06-11 14:43:14 +02:00
from c3nav.mapdata.models.level import Level
from c3nav.mapdata.models.locations import LocationRedirect, SpecificLocation
2017-10-24 23:26:09 +02:00
from c3nav.mapdata.render.base import set_tile_access_cookie
from c3nav.mapdata.utils.locations import get_location_by_slug_for_request
2016-12-15 17:30:55 +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'
def get_location_or_404(request, location):
if location is None:
return None
2016-12-15 18:28:04 +01:00
2017-05-12 01:21:53 +02:00
get_location = None
location = get_location(request, location)
if location is None:
raise Http404
2016-12-15 18:28:04 +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
def check_location(location: Optional[str], request) -> Optional[SpecificLocation]:
if location is None:
return None
location = get_location_by_slug_for_request(location, request)
if location is None:
return
if isinstance(location, LocationRedirect):
location: Location = location.target
if location is None:
return None
if not location.can_search:
location = None
return location
def get_levels(request) -> Mapping[int, Level]:
cache_key = 'mapdata:levels:%s' % AccessPermission.cache_key_for_request(request)
levels = cache.get(cache_key, None)
if levels is not None:
return levels
levels = OrderedDict(
(level.slug, (level.pk, level.slug, level.short_label))
for level in Level.qs_for_request(request).order_by('base_altitude')
)
cache.set(cache_key, levels, 300)
return levels
2017-10-31 15:37:19 +01:00
def map_index(request, origin=None, destination=None, level=None, x=None, y=None, zoom=None):
2017-10-25 12:15:19 +02:00
levels = Level.qs_for_request(request).filter(on_top_of_id__isnull=True)
2017-10-31 15:37:19 +01:00
origin_slug, destination_slug = origin, destination
origin = check_location(origin or None, request)
destination = check_location(destination or None, request)
state = {
2017-10-31 15:37:19 +01:00
'routing': origin_slug is not None,
'origin': (origin.serialize(detailed=False, simple_geometry=True, geometry=False)
if origin else None),
'destination': (destination.serialize(detailed=False, simple_geometry=True, geometry=False)
if destination else None),
2017-10-31 15:37:19 +01:00
'sidebar': destination_slug is not None,
}
levels_cache_key = 'mapdata:levels:%s' % AccessPermission.cache_key_for_request(request)
levels = cache.get(levels_cache_key, None)
if levels is None:
levels = OrderedDict(
(level.slug, (level.pk, level.slug, level.short_label))
for level in Level.qs_for_request(request).order_by('base_altitude')
)
cache.set(levels_cache_key, levels, 300)
level = levels.get(level, None) if level else None
if level is not None:
state.update({
'level': level[0],
'center': (float(x), float(y)),
'zoom': float(zoom),
})
ctx = {
2017-10-25 12:15:19 +02:00
'bounds': json.dumps(Source.max_bounds(), separators=(',', ':')),
'levels': json.dumps(tuple(levels.values()), separators=(',', ':')),
'state': json.dumps(state, separators=(',', ':')),
}
2017-10-24 23:26:09 +02:00
response = render(request, 'site/map.html', ctx)
set_tile_access_cookie(request, response)
return response
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'
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 22:20:42 +01:00
width, height = get_dimensions()
2017-05-07 12:06:13 +02:00
sections = tuple(section for id_, section in get_sections_cached().items())
2016-12-20 22:20:42 +01:00
ctx.update({
'width': width,
'height': height,
'svg_width': int(width * 6),
'svg_height': int(height * 6),
2017-05-07 12:06:13 +02:00
'sections': sections,
2016-12-20 22:20:42 +01:00
})
map_level = request.GET.get('map-level')
2017-05-07 12:06:13 +02:00
if map_level in sections:
2016-12-20 22:20:42 +01:00
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():
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
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'
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
result.url = reverse(url, kwargs=kwargs)
ctx.update({
2016-12-20 22:20:42 +01:00
'search': active_field,
'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 23:58:12 +01:00
save_settings = False
if 'c3nav_settings' in request.COOKIES:
cookie_value = request.COOKIES['c3nav_settings']
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
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)
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-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
if request.method == 'POST':
2016-12-19 23:58:12 +01:00
save_settings = request.POST.get('save_settings', '') == '1'
ctx.update({
'stairs': stairs,
'escalators': escalators,
'elevators': elevators,
2016-12-21 13:31:56 +01:00
'excludables': avoidables.items(),
'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-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'})
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-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()})
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