add RouteOptions

This commit is contained in:
Laura Klünder 2017-12-12 23:09:15 +01:00
parent 9fe2bc4533
commit d3dc6ae02e
4 changed files with 195 additions and 0 deletions

View file

@ -7,6 +7,7 @@ from c3nav.mapdata.models.access import AccessPermission
from c3nav.mapdata.utils.locations import visible_locations_for_request
from c3nav.routing.exceptions import LocationUnreachable, NoRouteFound, NotYetRoutable
from c3nav.routing.forms import RouteForm
from c3nav.routing.models import RouteOptions
from c3nav.routing.router import Router
@ -45,3 +46,22 @@ class RoutingViewSet(ViewSet):
},
'result': route.serialize(locations=visible_locations_for_request(request)),
})
@list_route(methods=['get', 'post'])
def options(self, request, *args, **kwargs):
params = request.POST if request.method == 'POST' else request.GET
if request.method == 'POST' or 'save' in params:
pass
options = RouteOptions.get_for_request(request)
return Response({
'options': options.data,
'fields': {
name: {
'type': field.widget.input_type,
'label': field.label,
'choices': dict(field.choices),
}
for name, field in options.get_fields().items()},
})

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 22:03
from __future__ import unicode_literals
import c3nav.mapdata.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0008_alter_user_username_max_length'),
]
operations = [
migrations.CreateModel(
name='RouteOptions',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='routeoptions', serialize=False, to=settings.AUTH_USER_MODEL)),
('data', c3nav.mapdata.fields.JSONField(default={})),
],
options={
'verbose_name': 'Route options',
'verbose_name_plural': 'Route options',
'default_related_name': 'routeoptions',
},
),
]

View file

143
src/c3nav/routing/models.py Normal file
View file

@ -0,0 +1,143 @@
import threading
from collections import OrderedDict
from django import forms
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
from c3nav.mapdata.fields import JSONField
from c3nav.mapdata.models import MapUpdate, WayType
class RouteOptions(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
data = JSONField(default={})
class Meta:
verbose_name = _('Route options')
verbose_name_plural = _('Route options')
default_related_name = 'routeoptions'
fields_cached = None
fields_cache_key = None
fields_cache_lock = threading.Lock()
@classmethod
def build_fields(cls):
fields = OrderedDict()
fields['walk_speed'] = forms.ChoiceField(
label=_('Walk speed'),
choices=(('slow', _('slow')), ('default', _('default')), ('fast', _('fast'))),
initial='default'
)
for waytype in WayType.objects.all():
choices = []
choices.append(('allow', _('allow')))
if waytype.up_separate:
choices.append(('avoid_up', _('avoid upwards')))
choices.append(('avoid_down', _('avoid downwards')))
choices.append(('avoid', _('avoid completely')))
else:
choices.append(('avoid', _('avoid')))
fields['waytype_%d' % waytype.pk] = forms.ChoiceField(
label=waytype.title_plural,
choices=tuple(choices),
initial='allow'
)
return fields
@classmethod
def get_fields(cls):
cache_key = MapUpdate.current_cache_key()
if cls.fields_cache_key != cache_key:
with cls.fields_cache_lock:
cls.fields_cache_key = cache_key
cls.fields_cached = cls.build_fields()
return cls.fields_cached
@staticmethod
def get_cache_key(pk):
return 'routing:options:user:%d' % pk
@classmethod
def get_for_user(cls, user):
cache_key = cls.get_cache_key(user.pk)
result = cache.get(cache_key, None)
if result:
return result
try:
result = user.routeoptions
except AttributeError:
result = None
if result:
cache.set(cache_key, result, 900)
return result
@classmethod
def get_for_request(cls, request):
session_options = request.session.get('route_options', None)
user_options = None
if request.user.is_authenticated:
user_options = cls.get_for_user(request.user)
if session_options and not user_options:
user_options = session_options
user_options.user = request.user
user_options.save()
request.session.pop('session_options')
options = cls(request=request)
options.update(user_options or session_options or {}, ignore_errors=True)
return options
def __init__(self, *args, request=None, **kwargs):
super().__init__(*args, **kwargs)
new_data = OrderedDict()
for name, field in self.get_fields().items():
value = self.data.get(name)
if value is None or value not in dict(field.choices):
value = field.initial
new_data[name] = value
self.data = new_data
self.request = request
def __getitem__(self, key):
try:
return self.data[key]
except AttributeError:
return self.get_fields()[key].initial
def update(self, value_dict, ignore_errors=False):
if not value_dict:
return
fields = self.get_fields()
for key, value in value_dict.items():
field = fields.get(key)
if not field:
if ignore_errors:
continue
raise ValidationError(_('Unknown route option: %s') % key)
if value is None or value not in dict(field.choices):
if ignore_errors:
continue
raise ValidationError(_('Invalid value for route option %s.') % key)
self.data[key] = value
def __setitem__(self, key, value):
self.update({key: value})
def save(self, *args, **kwargs):
if self.request is None or self.request.user.is_authenticated:
self.user = self.request.user
super().save(*args, **kwargs)
self.request.session['route_options'] = self