api for setting positions

This commit is contained in:
Laura Klünder 2019-12-28 16:35:38 +01:00
parent 01befdedb8
commit 399ac98c1c
3 changed files with 54 additions and 3 deletions

View file

@ -15,10 +15,11 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import NotFound, ValidationError from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.generics import get_object_or_404 from rest_framework.generics import get_object_or_404
from rest_framework.mixins import RetrieveModelMixin from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet, ViewSet from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet, ViewSet
from c3nav.mapdata.forms import PositionAPIUpdateForm
from c3nav.mapdata.models import AccessRestriction, Building, Door, Hole, LocationGroup, MapUpdate, Source, Space from c3nav.mapdata.models import AccessRestriction, Building, Door, Hole, LocationGroup, MapUpdate, Source, Space
from c3nav.mapdata.models.access import AccessPermission, AccessRestrictionGroup from c3nav.mapdata.models.access import AccessPermission, AccessRestrictionGroup
from c3nav.mapdata.models.geometry.base import GeometryMixin from c3nav.mapdata.models.geometry.base import GeometryMixin
@ -464,7 +465,7 @@ class LocationBySlugViewSet(LocationViewSetBase):
return get_location_by_slug_for_request(self.kwargs['slug'], self.request) return get_location_by_slug_for_request(self.kwargs['slug'], self.request)
class DynamicLocationPositionViewSet(RetrieveModelMixin, GenericViewSet): class DynamicLocationPositionViewSet(UpdateModelMixin, RetrieveModelMixin, GenericViewSet):
queryset = LocationSlug.objects.all() queryset = LocationSlug.objects.all()
lookup_field = 'slug' lookup_field = 'slug'
lookup_value_regex = r'[^/]+' lookup_value_regex = r'[^/]+'
@ -482,6 +483,20 @@ class DynamicLocationPositionViewSet(RetrieveModelMixin, GenericViewSet):
obj = self.get_object() obj = self.get_object()
return Response(obj.serialize_position()) return Response(obj.serialize_position())
def update(self, request, *args, **kwargs):
instance = self.get_object()
params = request.data
form = PositionAPIUpdateForm(instance=instance, data=params, request=request)
if not form.is_valid():
return Response({
'errors': form.errors,
}, status=400)
form.save()
return Response(form.instance.serialize_position())
class SourceViewSet(MapdataViewSet): class SourceViewSet(MapdataViewSet):
queryset = Source.objects.all() queryset = Source.objects.all()

View file

@ -8,6 +8,8 @@ from django.utils.translation import get_language_info
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from c3nav.mapdata.fields import I18nField from c3nav.mapdata.fields import I18nField
from c3nav.mapdata.models.locations import Position
from c3nav.mapdata.utils.locations import get_location_by_id_for_request
class I18nModelFormMixin(ModelForm): class I18nModelFormMixin(ModelForm):
@ -62,3 +64,36 @@ class I18nModelFormMixin(ModelForm):
super().full_clean() super().full_clean()
for field, values in self.i18n_fields: for field, values in self.i18n_fields:
setattr(self.instance, field.attname, {lang: value for lang, value in values.items() if value}) setattr(self.instance, field.attname, {lang: value for lang, value in values.items() if value})
class PositionAPIUpdateForm(ModelForm):
secret = CharField()
def __init__(self, *args, request=None, **kwargs):
self.request = request
super().__init__(*args, **kwargs)
class Meta:
model = Position
fields = ['coordinates_id', 'timeout']
def clean_secret(self):
# not called api_secret so we don't overwrite it
api_secret = self.cleaned_data['secret']
if api_secret != self.instance.api_secret:
raise ValidationError(_('Wrong API secret.'))
return api_secret
def clean_coordinates_id(self):
coordinates_id = self.cleaned_data['coordinates_id']
if coordinates_id is None:
return coordinates_id
if not coordinates_id.startswith('c:'):
raise ValidationError(_('Invalid coordinates.'))
coordinates = get_location_by_id_for_request(self.cleaned_data['coordinates_id'], self.request)
if coordinates is None:
raise ValidationError(_('Invalid coordinates.'))
return coordinates_id

View file

@ -566,7 +566,8 @@ class Position(CustomLocationProxyMixin, models.Model):
name = models.CharField(_('name'), max_length=32) name = models.CharField(_('name'), max_length=32)
secret = models.CharField(_('secret'), unique=True, max_length=32, default=get_position_secret) secret = models.CharField(_('secret'), unique=True, max_length=32, default=get_position_secret)
last_coordinates_update = models.DateTimeField(_('last coordinates update'), null=True) last_coordinates_update = models.DateTimeField(_('last coordinates update'), null=True)
timeout = models.PositiveSmallIntegerField(_('timeout (in seconds)'), default=0, help_text=_('0 for no timeout')) timeout = models.PositiveSmallIntegerField(_('timeout (in seconds)'), default=0, blank=True,
help_text=_('0 for no timeout'))
coordinates_id = models.CharField(_('coordinates'), null=True, max_length=48) coordinates_id = models.CharField(_('coordinates'), null=True, max_length=48)
api_secret = models.CharField(_('api secret'), max_length=64, default=get_position_api_secret) api_secret = models.CharField(_('api secret'), max_length=64, default=get_position_api_secret)