mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
* Do not show objects in status "pending" on the UI #784 * Fix peeringdb.js bug introduced in #784 * 500 Error during login for 2FA enabled accounts with unverified email address #996 * Django-Admin: adding a network with existing asn fails with internal error #1035 * Some command-line-tool executions are not logged #1119 * Ops: API throttling of repeated requests #1126 * Ops: response header X-Auth-ID to augment logging #1120 * Allow rate-limiting of melissa enabled api functionality. #1124 * State / Province normalization #1079 * Log melissa requests #1122 * remove debug messages * bump django-handleref to 1.0.2 * Need consolidated app logs #845 * pin django peeringdb to 2.13 and relock poetry * pin django-restframework-apikey to 2.1.0 * linting * migrations * docs regenerate * docs * linting Co-authored-by: David Poarch <dpoarch@20c.com> Co-authored-by: Stefan Pratter <stefan@20c.com>
114 lines
2.9 KiB
Python
114 lines
2.9 KiB
Python
"""
|
|
REST API renderer.
|
|
|
|
Ensure valid json output of the REST API.
|
|
"""
|
|
|
|
import json
|
|
|
|
from rest_framework import renderers
|
|
from rest_framework.utils import encoders
|
|
|
|
from peeringdb_server.rest_throttles import ResponseSizeThrottle
|
|
|
|
|
|
class JSONEncoder(encoders.JSONEncoder):
|
|
"""
|
|
Define json encoder to be able to encode
|
|
datatime and django countryfields.
|
|
|
|
Make the munge renderer use this encoder to encode json. This approach
|
|
may need to be tidied up a bit.
|
|
"""
|
|
|
|
def default(self, obj):
|
|
"""Default JSON serializer."""
|
|
import datetime
|
|
|
|
import django_countries.fields
|
|
|
|
if isinstance(obj, datetime.datetime):
|
|
return obj.isoformat()
|
|
|
|
if isinstance(obj, django_countries.fields.Country):
|
|
return str(obj)
|
|
|
|
return encoders.JSONEncoder.default(self, obj)
|
|
|
|
|
|
class MungeRenderer(renderers.BaseRenderer):
|
|
media_type = "text/plain"
|
|
format = "txt"
|
|
charset = "utf-8"
|
|
|
|
def render(self, data, media_type=None, renderer_context=None):
|
|
# TODO use munge:
|
|
indent = None
|
|
if "request" in renderer_context:
|
|
request = renderer_context.get("request")
|
|
if "pretty" in request.GET:
|
|
indent = 2
|
|
return json.dumps(data, cls=JSONEncoder, indent=indent)
|
|
|
|
|
|
class MetaJSONRenderer(MungeRenderer):
|
|
"""
|
|
Renderer which serializes to JSON.
|
|
Does *not* apply JSON's character escaping for non-ascii characters.
|
|
"""
|
|
|
|
ensure_ascii = False
|
|
|
|
media_type = "application/json"
|
|
format = "json"
|
|
|
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
|
"""
|
|
Tweak output rendering and pass to parent.
|
|
"""
|
|
|
|
if data is None:
|
|
return bytes()
|
|
|
|
result = {}
|
|
|
|
if "__meta" in data:
|
|
meta = data.pop("__meta")
|
|
else:
|
|
meta = dict()
|
|
|
|
if "request" in renderer_context:
|
|
request = renderer_context.get("request")
|
|
meta.update(getattr(request, "meta_response", {}))
|
|
else:
|
|
request = None
|
|
|
|
res = renderer_context["response"]
|
|
if res.status_code < 400:
|
|
if "results" in data:
|
|
result["data"] = data.pop("results")
|
|
elif data:
|
|
if isinstance(data, dict):
|
|
result["data"] = [data]
|
|
else:
|
|
result["data"] = [r for r in data if r is not None]
|
|
else:
|
|
result["data"] = []
|
|
|
|
elif res.status_code < 500:
|
|
meta["error"] = data.pop("detail", res.reason_phrase)
|
|
|
|
result.update(**data)
|
|
|
|
result["meta"] = meta
|
|
|
|
rendered_content = super(self.__class__, self).render(
|
|
result, accepted_media_type, renderer_context
|
|
)
|
|
|
|
# handle caching of response size (#1129)
|
|
if request:
|
|
ResponseSizeThrottle.cache_response_size(request, len(rendered_content))
|
|
|
|
return rendered_content
|