diff --git a/src/c3nav/api/__init__.py b/src/c3nav/api/__init__.py index e69de29b..63b50dbe 100644 --- a/src/c3nav/api/__init__.py +++ b/src/c3nav/api/__init__.py @@ -0,0 +1,15 @@ +from rest_framework.renderers import JSONRenderer +from ..mapdata.utils import json_encoder_reindent +from functools import wraps + +orig_render = JSONRenderer.render + + +@wraps(JSONRenderer.render) +def nicer_renderer(self, data, accepted_media_type=None, renderer_context=None): + if self.get_indent(accepted_media_type, renderer_context) is None: + return orig_render(self, data, accepted_media_type, renderer_context) + return json_encoder_reindent(lambda d: orig_render(self, d, accepted_media_type, renderer_context), data) + +# Monkey patch for nicer indentation in the django rest framework +JSONRenderer.render = nicer_renderer diff --git a/src/c3nav/api/permissions.py b/src/c3nav/api/permissions.py index 434a2497..45a06df4 100644 --- a/src/c3nav/api/permissions.py +++ b/src/c3nav/api/permissions.py @@ -1,5 +1,6 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ + from rest_framework.exceptions import PermissionDenied from rest_framework.permissions import BasePermission diff --git a/src/c3nav/api/serializers.py b/src/c3nav/api/serializers.py index a971cea3..6ec9d342 100644 --- a/src/c3nav/api/serializers.py +++ b/src/c3nav/api/serializers.py @@ -1,4 +1,5 @@ from django.conf import settings + from rest_framework import serializers from ..editor.hosters import get_hoster_for_package @@ -6,24 +7,16 @@ from ..mapdata.models import Level, Package, Source from .permissions import can_access_package -class BoundsMixin: - def to_representation(self, obj): - result = super().to_representation(obj) - if obj.bottom is not None: - result['bounds'] = ((obj.bottom, obj.left), (obj.top, obj.right)) - return result - - class LevelSerializer(serializers.ModelSerializer): class Meta: model = Level fields = ('name', 'altitude', 'package') -class PackageSerializer(BoundsMixin, serializers.ModelSerializer): +class PackageSerializer(serializers.ModelSerializer): class Meta: model = Package - fields = ('name', 'home_repo', 'depends') + fields = ('name', 'home_repo', 'depends', 'bounds') def to_representation(self, obj): result = super().to_representation(obj) @@ -36,10 +29,10 @@ class PackageSerializer(BoundsMixin, serializers.ModelSerializer): return result -class SourceSerializer(BoundsMixin, serializers.ModelSerializer): +class SourceSerializer(serializers.ModelSerializer): class Meta: model = Source - fields = ('name', 'package') + fields = ('name', 'package', 'bounds') class HosterSerializer(serializers.Serializer): diff --git a/src/c3nav/api/urls.py b/src/c3nav/api/urls.py index 68484981..9b360041 100644 --- a/src/c3nav/api/urls.py +++ b/src/c3nav/api/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import include, url + from rest_framework.routers import DefaultRouter from .views import editor as editor_views diff --git a/src/c3nav/api/views/editor.py b/src/c3nav/api/views/editor.py index 76c625dc..b754ef7a 100644 --- a/src/c3nav/api/views/editor.py +++ b/src/c3nav/api/views/editor.py @@ -1,4 +1,5 @@ from django.http import Http404 + from rest_framework.response import Response from rest_framework.viewsets import ViewSet diff --git a/src/c3nav/api/views/mapdata.py b/src/c3nav/api/views/mapdata.py index 1fc07317..27a18d8b 100644 --- a/src/c3nav/api/views/mapdata.py +++ b/src/c3nav/api/views/mapdata.py @@ -4,6 +4,7 @@ import os from django.conf import settings from django.core.files import File from django.http import HttpResponse + from rest_framework.decorators import detail_route from rest_framework.viewsets import ReadOnlyModelViewSet diff --git a/src/c3nav/mapdata/models/package.py b/src/c3nav/mapdata/models/package.py index 1dbbe7db..581c85de 100644 --- a/src/c3nav/mapdata/models/package.py +++ b/src/c3nav/mapdata/models/package.py @@ -54,6 +54,12 @@ class Package(models.Model): def package(self): return self + @property + def bounds(self): + if self.bottom is None: + return None + return ((float(self.bottom), float(self.left)), (float(self.top), float(self.right))) + def tofile(self): data = OrderedDict() data['name'] = self.name diff --git a/src/c3nav/mapdata/models/source.py b/src/c3nav/mapdata/models/source.py index 2b8ae19c..ee1aa560 100644 --- a/src/c3nav/mapdata/models/source.py +++ b/src/c3nav/mapdata/models/source.py @@ -1,5 +1,3 @@ -import json - from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -26,11 +24,7 @@ class Source(models.Model): @property def bounds(self): - return ((self.bottom, self.left), (self.top, self.right)) - - @property - def jsbounds(self): - return json.dumps(((float(self.bottom), float(self.left)), (float(self.top), float(self.right)))) + return ((float(self.bottom), float(self.left)), (float(self.top), float(self.right))) @classmethod def fromfile(cls, data, package, name): diff --git a/src/c3nav/mapdata/packageio/utils.py b/src/c3nav/mapdata/packageio/utils.py index 10143050..56e8095e 100644 --- a/src/c3nav/mapdata/packageio/utils.py +++ b/src/c3nav/mapdata/packageio/utils.py @@ -3,6 +3,7 @@ import json from django.core.management.base import CommandError from ..models import Level, Package, Source +from ..utils import json_encoder_reindent class ObjectCollection: @@ -93,25 +94,5 @@ class ObjectCollection: print('- Added dependency: '+depname) -def _preencode(data, magic_marker): - if isinstance(data, dict): - data = data.copy() - for name, value in tuple(data.items()): - if name in ('bounds', ): - data[name] = magic_marker+json.dumps(value)+magic_marker - else: - data[name] = _preencode(value, magic_marker) - return data - elif isinstance(data, (tuple, list)): - return tuple(_preencode(value, magic_marker) for value in data) - else: - return data - - def json_encode(data): - magic_marker = '***JSON_MAGIC_MARKER***' - test_encode = json.dumps(data) - while magic_marker in test_encode: - magic_marker += '*' - result = json.dumps(_preencode(data, magic_marker), indent=4) - return result.replace('"'+magic_marker, '').replace(magic_marker+'"', '')+'\n' + return json_encoder_reindent(json.dumps, data, indent=4)+'\n' diff --git a/src/c3nav/mapdata/utils.py b/src/c3nav/mapdata/utils.py new file mode 100644 index 00000000..4dcdb21f --- /dev/null +++ b/src/c3nav/mapdata/utils.py @@ -0,0 +1,29 @@ +import json + + +def _preencode(data, magic_marker): + if isinstance(data, dict): + data = data.copy() + for name, value in tuple(data.items()): + if name in ('bounds', ): + data[name] = magic_marker+json.dumps(value)+magic_marker + else: + data[name] = _preencode(value, magic_marker) + return data + elif isinstance(data, (tuple, list)): + return tuple(_preencode(value, magic_marker) for value in data) + else: + return data + + +def json_encoder_reindent(method, data, *args, **kwargs): + magic_marker = '***JSON_MAGIC_MARKER***' + test_encode = json.dumps(data) + while magic_marker in test_encode: + magic_marker += '*' + result = method(_preencode(data, magic_marker), *args, **kwargs) + if type(result) == str: + return result.replace('"'+magic_marker, '').replace(magic_marker+'"', '') + else: + magic_marker = magic_marker.encode() + return result.replace(b'"'+magic_marker, b'').replace(magic_marker+b'"', b'')