add RouteOptions
This commit is contained in:
parent
9fe2bc4533
commit
d3dc6ae02e
4 changed files with 195 additions and 0 deletions
|
@ -7,6 +7,7 @@ from c3nav.mapdata.models.access import AccessPermission
|
||||||
from c3nav.mapdata.utils.locations import visible_locations_for_request
|
from c3nav.mapdata.utils.locations import visible_locations_for_request
|
||||||
from c3nav.routing.exceptions import LocationUnreachable, NoRouteFound, NotYetRoutable
|
from c3nav.routing.exceptions import LocationUnreachable, NoRouteFound, NotYetRoutable
|
||||||
from c3nav.routing.forms import RouteForm
|
from c3nav.routing.forms import RouteForm
|
||||||
|
from c3nav.routing.models import RouteOptions
|
||||||
from c3nav.routing.router import Router
|
from c3nav.routing.router import Router
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,3 +46,22 @@ class RoutingViewSet(ViewSet):
|
||||||
},
|
},
|
||||||
'result': route.serialize(locations=visible_locations_for_request(request)),
|
'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()},
|
||||||
|
})
|
||||||
|
|
32
src/c3nav/routing/migrations/0001_routeoptions.py
Normal file
32
src/c3nav/routing/migrations/0001_routeoptions.py
Normal 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',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
src/c3nav/routing/migrations/__init__.py
Normal file
0
src/c3nav/routing/migrations/__init__.py
Normal file
143
src/c3nav/routing/models.py
Normal file
143
src/c3nav/routing/models.py
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue