add feature views to api and editor.js

This commit is contained in:
Laura Klünder 2016-10-13 13:55:02 +02:00
parent 0036b27057
commit 4b74eb0cf5
13 changed files with 216 additions and 178 deletions

0
src/__init__.py Normal file
View file

View file

@ -8,14 +8,19 @@ from rest_framework.response import Response
from rest_framework.routers import SimpleRouter
from c3nav.editor.api import HosterViewSet, SubmitTaskViewSet
from c3nav.mapdata.api import FeatureTypeViewSet, FeatureViewSet, LevelViewSet, PackageViewSet, SourceViewSet
from c3nav.mapdata.api.features import FeatureTypeViewSet, FeatureViewSet, InsideViewSet, RoomViewSet
from c3nav.mapdata.api.main import LevelViewSet, PackageViewSet, SourceViewSet
router = SimpleRouter()
router.register(r'levels', LevelViewSet)
router.register(r'packages', PackageViewSet)
router.register(r'sources', SourceViewSet)
router.register(r'featuretypes', FeatureTypeViewSet, base_name='featuretype')
router.register(r'features', FeatureViewSet, base_name='feature')
router.register(r'features', FeatureViewSet, base_name='features')
router.register(r'insides', InsideViewSet)
router.register(r'rooms', RoomViewSet)
router.register(r'hosters', HosterViewSet, base_name='hoster')
router.register(r'submittasks', SubmitTaskViewSet, base_name='submittask')

View file

@ -186,35 +186,36 @@ editor = {
features: {},
get_features: function () {
$.getJSON('/api/features/', function(features) {
var feature_type;
for (var level in editor.levels) {
$.getJSON('/api/features/', function(all_features) {
$('.feature_level_list li').remove();
var feature_type, features, feature, layergroup;
for (var j = 0; j < editor.feature_types_order.length; j++) {
feature_type = editor.feature_types_order[j];
for (var level in editor.levels) {
editor.level_feature_layers[level][feature_type].clearLayers();
}
}
$('.feature_level_list li').remove();
var feature, layergroup;
features = all_features[editor.feature_types[feature_type].endpoint]
for (var i = 0; i < features.length; i++) {
feature = features[i];
console.log(feature);
layergroup = L.geoJSON({
type: 'Feature',
geometry: feature.geometry,
properties: {
name: feature.name,
feature_type: feature.feature_type
feature_type: feature_type
}
}, {
style: editor._get_feature_style
}).on('mouseover', editor._hover_feature_layer)
.on('mouseout', editor._unhover_feature_layer)
.on('click', editor._click_feature_layer)
.addTo(editor.level_feature_layers[feature.level][feature.feature_type]);
.addTo(editor.level_feature_layers[feature.level][feature_type]);
feature.layer = layergroup.getLayers()[0];
editor.features[feature.name] = feature;
$('.feature_list[name='+feature.feature_type+'] > [data-level='+feature.level+']').append(
$('.feature_list[name=' + feature_type + '] > [data-level=' + feature.level + ']').append(
$('<li>').attr('name', feature.name).append(
$('<p>').text(feature.title).append(' ').append(
$('<em>').text(feature.name)
@ -222,6 +223,7 @@ editor = {
)
);
}
}
$('.start-drawing').show();
$('#mapeditcontrols').addClass('list');
editor.set_current_level(editor._level);
@ -319,7 +321,8 @@ editor = {
editor.map.fitBounds(editor._editing.getBounds());
$('.leaflet-drawbar').hide();
var path = '/editor/features/' + editor._creating + '/add/';
var endpoint = editor.feature_types[editor._creating].endpoint;
var path = '/editor/' + endpoint + '/add/';
$('#mapeditcontrols').removeClass('list');
$('body').addClass('controls');
$('#mapeditdetail').load(path, editor.edit_form_loaded);
@ -330,7 +333,8 @@ editor = {
if (editor._creating !== null || editor._editing !== null) return;
editor._highlight_layer.clearLayers();
editor._editing = editor.features[name].layer;
var path = '/editor/features/edit/' + name + '/';
var endpoint = editor.feature_types[editor._editing.feature.properties.feature_type].endpoint;
var path = '/editor/'+endpoint+'/edit/' + name + '/';
$('#mapeditcontrols').removeClass('list');
$('#mapeditdetail').load(path, editor.edit_form_loaded);
$('body').addClass('controls');

View file

View file

@ -0,0 +1,60 @@
from collections import OrderedDict
from django.http import Http404
from rest_framework.response import Response
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
from c3nav.mapdata.models import FEATURE_TYPES
from c3nav.mapdata.models.features import Inside, Room
from c3nav.mapdata.serializers.features import FeatureTypeSerializer, InsideSerializer, RoomSerializer
class FeatureTypeViewSet(ViewSet):
"""
List and retrieve feature types
"""
lookup_field = 'name'
def list(self, request):
serializer = FeatureTypeSerializer(FEATURE_TYPES.values(), many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk=None):
if pk not in FEATURE_TYPES:
raise Http404
serializer = FeatureTypeSerializer(FEATURE_TYPES[pk], context={'request': request})
return Response(serializer.data)
class FeatureViewSet(ViewSet):
"""
List all features.
This endpoint combines the list endpoints for all feature types.
"""
def list(self, request):
result = OrderedDict()
for name, model in FEATURE_TYPES.items():
endpoint = model._meta.default_related_name
result[endpoint] = eval(model.__name__+'ViewSet').as_view({'get': 'list'})(request).data
return Response(result)
class InsideViewSet(ReadOnlyModelViewSet):
"""
List and retrieve Inside Areas
"""
queryset = Inside.objects.all()
serializer_class = InsideSerializer
lookup_field = 'name'
lookup_value_regex = '[^/]+'
class RoomViewSet(ReadOnlyModelViewSet):
"""
List and retrieve Rooms
"""
queryset = Room.objects.all()
serializer_class = RoomSerializer
lookup_field = 'name'
lookup_value_regex = '[^/]+'

View file

@ -1,19 +1,15 @@
import mimetypes
import os
from itertools import chain
from django.conf import settings
from django.core.files import File
from django.http import Http404, HttpResponse
from django.http import HttpResponse
from rest_framework.decorators import detail_route
from rest_framework.response import Response
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet
from c3nav.mapdata.models import FEATURE_TYPES, Level, Package, Source
from c3nav.mapdata.models.features import Feature
from c3nav.mapdata.models import Level, Package, Source
from c3nav.mapdata.permissions import filter_source_queryset
from c3nav.mapdata.serializers import (FeatureSerializer, FeatureTypeSerializer, LevelSerializer, PackageSerializer,
SourceSerializer)
from c3nav.mapdata.serializers.main import LevelSerializer, PackageSerializer, SourceSerializer
class LevelViewSet(ReadOnlyModelViewSet):
@ -68,38 +64,3 @@ class SourceViewSet(ReadOnlyModelViewSet):
for chunk in File(open(image_path, 'rb')).chunks():
response.write(chunk)
return response
class FeatureTypeViewSet(ViewSet):
"""
List and retrieve feature types
"""
lookup_field = 'name'
def list(self, request):
serializer = FeatureTypeSerializer(FEATURE_TYPES.values(), many=True, context={'request': request})
return Response(serializer.data)
def retrieve(self, request, pk=None):
if pk not in FEATURE_TYPES:
raise Http404
serializer = FeatureTypeSerializer(FEATURE_TYPES[pk], context={'request': request})
return Response(serializer.data)
class FeatureViewSet(ReadOnlyModelViewSet):
"""
List and retrieve map features you have access to
"""
model = Feature
base_name = 'feature'
serializer_class = FeatureSerializer
lookup_field = 'name'
lookup_value_regex = '[^/]+'
def get_queryset(self):
querysets = []
for name, model in FEATURE_TYPES.items():
querysets.append(model.objects.all())
return chain(*querysets)

View file

@ -30,4 +30,3 @@ class MapdataModel(models.Model):
class Meta:
abstract = True
unique_together = ('package', 'name')

View file

@ -1,17 +1,16 @@
import os
from collections import OrderedDict
from django.db import models
from django.utils.translation import ugettext_lazy as _
from shapely.geometry.geo import shape, mapping
from shapely.geometry.geo import mapping, shape
from c3nav.mapdata.fields import GeometryField
from c3nav.mapdata.models.base import MapdataModel
from c3nav.mapdata.utils import format_geojson
FEATURE_TYPES = OrderedDict()
def register_featuretype(cls):
FEATURE_TYPES[cls.__name__.lower()] = cls
return cls
@ -77,5 +76,3 @@ class Room(Feature):
verbose_name = _('Room')
verbose_name_plural = _('Rooms')
default_related_name = 'rooms'

View file

@ -1,94 +0,0 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from shapely.geometry import mapping, shape
from c3nav.editor.hosters import get_hoster_for_package
from c3nav.mapdata.models import Feature, Level, Package, Source
from c3nav.mapdata.utils import format_geojson
class GeometryField(serializers.DictField):
"""
shapely geometry objects serialized using GeoJSON
"""
default_error_messages = {
'invalid': _('Invalid GeoJSON.')
}
def to_representation(self, obj):
geojson = format_geojson(mapping(obj), round=False)
return super().to_representation(geojson)
def to_internal_value(self, data):
geojson = super().to_internal_value(data)
try:
return shape(geojson)
except:
raise ValidationError(_('Invalid GeoJSON.'))
class PackageSerializer(serializers.ModelSerializer):
hoster = serializers.SerializerMethodField()
depends = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
class Meta:
model = Package
fields = ('name', 'home_repo', 'commit_id', 'depends', 'bounds', 'public', 'hoster')
def get_depends(self, obj):
return self.recursive_value(PackageSerializer, obj.depends, many=True)
def get_hoster(self, obj):
return get_hoster_for_package(obj).name
class LevelSerializer(serializers.ModelSerializer):
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
class Meta:
model = Level
fields = ('name', 'altitude', 'package')
class SourceSerializer(serializers.ModelSerializer):
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
class Meta:
model = Source
fields = ('name', 'package', 'bounds')
class FeatureTypeSerializer(serializers.Serializer):
name = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
title_plural = serializers.SerializerMethodField()
geomtype = serializers.CharField()
color = serializers.CharField()
def get_name(self, obj):
return obj.__name__.lower()
def get_title(self, obj):
return str(obj._meta.verbose_name)
def get_title_plural(self, obj):
return str(obj._meta.verbose_name_plural)
class FeatureSerializer(serializers.Serializer):
name = serializers.CharField()
feature_type = serializers.SerializerMethodField()
level = serializers.SerializerMethodField()
package = serializers.SerializerMethodField()
geometry = GeometryField()
def get_feature_type(self, obj):
return obj.__class__.__name__.lower()
def get_level(self, obj):
return obj.level.name
def get_package(self, obj):
return obj.package.name

View file

@ -0,0 +1,45 @@
from rest_framework import serializers
from c3nav.mapdata.models.features import Inside, Room
from c3nav.mapdata.serializers.fields import GeometryField
class FeatureTypeSerializer(serializers.Serializer):
name = serializers.SerializerMethodField()
title = serializers.SerializerMethodField()
title_plural = serializers.SerializerMethodField()
endpoint = serializers.SerializerMethodField()
geomtype = serializers.CharField()
color = serializers.CharField()
def get_name(self, obj):
return obj.__name__.lower()
def get_title(self, obj):
return str(obj._meta.verbose_name)
def get_title_plural(self, obj):
return str(obj._meta.verbose_name_plural)
def get_endpoint(self, obj):
return obj._meta.default_related_name
class InsideSerializer(serializers.ModelSerializer):
level = serializers.SlugRelatedField(slug_field='name', read_only=True)
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
geometry = GeometryField()
class Meta:
model = Inside
fields = ('name', 'level', 'package', 'geometry')
class RoomSerializer(serializers.ModelSerializer):
level = serializers.SlugRelatedField(slug_field='name', read_only=True)
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
geometry = GeometryField()
class Meta:
model = Room
fields = ('name', 'level', 'package', 'geometry')

View file

@ -0,0 +1,26 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from shapely.geometry import mapping, shape
from c3nav.mapdata.utils import format_geojson
class GeometryField(serializers.DictField):
"""
shapely geometry objects serialized using GeoJSON
"""
default_error_messages = {
'invalid': _('Invalid GeoJSON.')
}
def to_representation(self, obj):
geojson = format_geojson(mapping(obj), round=False)
return super().to_representation(geojson)
def to_internal_value(self, data):
geojson = super().to_internal_value(data)
try:
return shape(geojson)
except:
raise ValidationError(_('Invalid GeoJSON.'))

View file

@ -0,0 +1,35 @@
from rest_framework import serializers
from c3nav.editor.hosters import get_hoster_for_package
from c3nav.mapdata.models import Level, Package, Source
class PackageSerializer(serializers.ModelSerializer):
hoster = serializers.SerializerMethodField()
depends = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True)
class Meta:
model = Package
fields = ('name', 'home_repo', 'commit_id', 'depends', 'bounds', 'public', 'hoster')
def get_depends(self, obj):
return self.recursive_value(PackageSerializer, obj.depends, many=True)
def get_hoster(self, obj):
return get_hoster_for_package(obj).name
class LevelSerializer(serializers.ModelSerializer):
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
class Meta:
model = Level
fields = ('name', 'altitude', 'package')
class SourceSerializer(serializers.ModelSerializer):
package = serializers.SlugRelatedField(slug_field='name', read_only=True)
class Meta:
model = Source
fields = ('name', 'package', 'bounds')