Add json-ld format on API endpoints
Signed-off-by: Alfredos-Panagiotis Damkalis <fredy@fredy.gr>spacecruft
parent
20153300cf
commit
67f229d2ed
|
@ -0,0 +1,17 @@
|
|||
"""SatNOGS DB django rest framework API custom renderers"""
|
||||
from rest_framework.renderers import JSONRenderer
|
||||
|
||||
from db.base.structured_data import get_structured_data
|
||||
|
||||
|
||||
class JSONLDRenderer(JSONRenderer):
|
||||
""" Renderer which serializes to JSONLD. """
|
||||
|
||||
media_type = 'application/ld+json'
|
||||
format = 'json-ld'
|
||||
|
||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||
""" Render `data` into JSONLD, returning a bytestring. """
|
||||
structured_data = get_structured_data(renderer_context['view'].basename, data)
|
||||
jsonld = structured_data.get_jsonld()
|
||||
return super(JSONLDRenderer, self).render(jsonld, accepted_media_type, renderer_context)
|
|
@ -4,23 +4,27 @@ from rest_framework import mixins, status, viewsets
|
|||
from rest_framework.parsers import FileUploadParser, FormParser, \
|
||||
MultiPartParser
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from db.api import filters, pagination, serializers
|
||||
from db.api.perms import SafeMethodsWithPermission
|
||||
from db.api.renderers import JSONLDRenderer
|
||||
from db.base.models import Artifact, DemodData, Mode, Satellite, Transmitter
|
||||
from db.base.tasks import update_satellite
|
||||
|
||||
|
||||
class ModeView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
||||
"""SatNOGS DB Mode API view class"""
|
||||
renderer_classes = [JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer]
|
||||
queryset = Mode.objects.all()
|
||||
serializer_class = serializers.ModeSerializer
|
||||
|
||||
|
||||
class SatelliteView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
||||
"""SatNOGS DB Satellite API view class"""
|
||||
renderer_classes = [JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer]
|
||||
queryset = Satellite.objects.all()
|
||||
serializer_class = serializers.SatelliteSerializer
|
||||
filter_class = filters.SatelliteViewFilter
|
||||
|
@ -29,6 +33,7 @@ class SatelliteView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
|||
|
||||
class TransmitterView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
||||
"""SatNOGS DB Transmitter API view class"""
|
||||
renderer_classes = [JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer]
|
||||
queryset = Transmitter.objects.all()
|
||||
serializer_class = serializers.TransmitterSerializer
|
||||
filter_class = filters.TransmitterViewFilter
|
||||
|
@ -39,6 +44,7 @@ class TelemetryView( # pylint: disable=R0901
|
|||
mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin,
|
||||
viewsets.GenericViewSet):
|
||||
"""SatNOGS DB Telemetry API view class"""
|
||||
renderer_classes = [JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer]
|
||||
queryset = DemodData.objects.all()
|
||||
serializer_class = serializers.TelemetrySerializer
|
||||
filter_class = filters.TelemetryViewFilter
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
"""SatNOGS DB structured data for models"""
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
from pyld import jsonld
|
||||
|
||||
|
||||
class StructuredData:
|
||||
"""Generic structered data class for models"""
|
||||
def __init__(self, data):
|
||||
self.context = {}
|
||||
self.data = data
|
||||
|
||||
def get_jsonld(self):
|
||||
"""Return JSONLD structure"""
|
||||
return {"@context": self.context, "@graph": self.data}
|
||||
|
||||
def get_context(self):
|
||||
"""Return the context of structured data"""
|
||||
return self.context
|
||||
|
||||
def get_data(self):
|
||||
"""Return the data of structured data"""
|
||||
return self.data
|
||||
|
||||
def get_expanded(self):
|
||||
"""Return expanded document form of JSONLD structure"""
|
||||
return jsonld.expand(self.get_jsonld())
|
||||
|
||||
def get_compacted(self, context):
|
||||
"""Return compacted document form of JSONLD structure given a context"""
|
||||
return jsonld.compact(self.get_jsonld(), context)
|
||||
|
||||
def get_flattened(self):
|
||||
"""Return flattened document form of JSONLD structure"""
|
||||
return jsonld.flatten(self.get_jsonld())
|
||||
|
||||
def get_framed(self, frame):
|
||||
"""Return framed document form of JSONLD structure given a frame"""
|
||||
return jsonld.frame(self.get_jsonld(), frame)
|
||||
|
||||
|
||||
class ModeStructuredData(StructuredData):
|
||||
"""Generic structered data class for Mode model"""
|
||||
def __init__(self, data):
|
||||
super(ModeStructuredData, self).__init__(data)
|
||||
self.context = {"@vocab": "https://schema.space/metasat/", "name": "modulation"}
|
||||
structured_data = []
|
||||
|
||||
for mode in data:
|
||||
structured_data.append({"name": mode['name']})
|
||||
self.data = structured_data
|
||||
|
||||
|
||||
class SatelliteStructuredData(StructuredData):
|
||||
"""Generic structered data class for Satellite model"""
|
||||
def __init__(self, data):
|
||||
super(SatelliteStructuredData, self).__init__(data)
|
||||
self.context = {
|
||||
"@vocab": "https://schema.space/metasat/",
|
||||
"schema": "http://schema.org/",
|
||||
"satellite": "satellite",
|
||||
"image": "schema:image",
|
||||
"name": "schema:name",
|
||||
"names": "schema:alternateName",
|
||||
"norad_cat_id": "noradID",
|
||||
"status": "status",
|
||||
"decoder": "decoder"
|
||||
}
|
||||
structured_data = []
|
||||
satellite_id_domain = Site.objects.get_current().domain + '/satellite/'
|
||||
|
||||
for satellite in data:
|
||||
data_to_append = {
|
||||
"satellite": {
|
||||
"@id": satellite_id_domain + str(satellite['norad_cat_id']),
|
||||
"norad_cat_id": satellite['norad_cat_id'],
|
||||
"name": satellite['name'],
|
||||
"status": satellite['status'],
|
||||
}
|
||||
}
|
||||
|
||||
if satellite['names']:
|
||||
data_to_append['satellite']['names'] = satellite['names'].replace('\r',
|
||||
'').split('\n')
|
||||
|
||||
if satellite['telemetries']:
|
||||
data_to_append['satellite']['decoder'] = []
|
||||
for decoder in satellite['telemetries']:
|
||||
data_to_append['satellite']['decoder'].append(decoder["decoder"])
|
||||
|
||||
structured_data.append(data_to_append)
|
||||
self.data = structured_data
|
||||
|
||||
|
||||
class TransmitterStructuredData(StructuredData):
|
||||
"""Generic structered data class for Transmitter model"""
|
||||
def __init__(self, data):
|
||||
super(TransmitterStructuredData, self).__init__(data)
|
||||
self.context = {
|
||||
"@vocab": "https://schema.space/metasat/",
|
||||
"schema": "http://schema.org/",
|
||||
"transmitter": "transmitter",
|
||||
"uuid": "schema:identifier",
|
||||
"type": None,
|
||||
"description": "schema:description",
|
||||
"status": "status",
|
||||
"mode": "modulation",
|
||||
"frequency": "frequency",
|
||||
"minimum": "schema:minimum",
|
||||
"maximum": "schema:maximum",
|
||||
"drift": "drift",
|
||||
"downlink": "downlink",
|
||||
"uplink": "uplink",
|
||||
"invert": None,
|
||||
"baud": "baudRate",
|
||||
"satellite": "satellite",
|
||||
"norad_cat_id": "noradID",
|
||||
"citation": "schema:citation",
|
||||
"service": "service"
|
||||
}
|
||||
structured_data = []
|
||||
transmitter_id_domain = Site.objects.get_current().domain + '/transmitter/'
|
||||
satellite_id_domain = Site.objects.get_current().domain + '/satellite/'
|
||||
|
||||
for transmitter in data:
|
||||
data_to_append = {
|
||||
"transmitter": {
|
||||
"@id": transmitter_id_domain + transmitter['uuid'],
|
||||
"uuid": transmitter['uuid'],
|
||||
"description": transmitter['description'],
|
||||
"type": transmitter['type'],
|
||||
"satellite": {
|
||||
"@id": satellite_id_domain + str(transmitter['norad_cat_id']),
|
||||
"norad_cat_id": transmitter['norad_cat_id']
|
||||
},
|
||||
"status": transmitter['status'],
|
||||
"citation": transmitter['citation'],
|
||||
"service": transmitter['service']
|
||||
}
|
||||
}
|
||||
|
||||
if transmitter['downlink_low']:
|
||||
if transmitter['downlink_high']:
|
||||
data_to_append['transmitter']['downlink'] = {
|
||||
"frequency": {
|
||||
"minimum": transmitter['downlink_low'],
|
||||
"maximum": transmitter['downlink_high']
|
||||
},
|
||||
"mode": transmitter['mode']
|
||||
}
|
||||
else:
|
||||
data_to_append['transmitter']['downlink'] = {
|
||||
"frequency": transmitter['downlink_low'],
|
||||
"mode": transmitter['mode']
|
||||
}
|
||||
if transmitter['downlink_drift']:
|
||||
data_to_append['transmitter']['downlink']['drift'
|
||||
] = transmitter['downlink_drift']
|
||||
|
||||
if transmitter['uplink_low']:
|
||||
if transmitter['uplink_high']:
|
||||
data_to_append['transmitter']['uplink'] = {
|
||||
"frequency": {
|
||||
"minimum": transmitter['uplink_low'],
|
||||
"maximum": transmitter['uplink_high']
|
||||
},
|
||||
"mode": transmitter['uplink_mode']
|
||||
}
|
||||
else:
|
||||
data_to_append['transmitter']['uplink'] = {
|
||||
"frequency": transmitter['uplink_low'],
|
||||
"mode": transmitter['uplink_mode']
|
||||
}
|
||||
if transmitter['uplink_drift']:
|
||||
data_to_append['transmitter']['uplink']['drift'] = transmitter['uplink_drift']
|
||||
|
||||
if transmitter['invert']:
|
||||
data_to_append['transmitter']['invert'] = transmitter['invert']
|
||||
|
||||
if transmitter['baud']:
|
||||
data_to_append['transmitter']['baud'] = transmitter['baud']
|
||||
|
||||
structured_data.append(data_to_append)
|
||||
self.data = structured_data
|
||||
|
||||
|
||||
class DemodDataStructuredData(StructuredData):
|
||||
"""Generic structered data class for DemodData model"""
|
||||
def __init__(self, data):
|
||||
super(DemodDataStructuredData, self).__init__(data)
|
||||
self.context = {
|
||||
"@vocab": "https://schema.space/metasat/",
|
||||
"schema": "http://schema.org/",
|
||||
"frame": "frame",
|
||||
"satellite": "satellite",
|
||||
"norad_cat_id": "noradID",
|
||||
"observer": "groundStation",
|
||||
"ground_station_locator": "maidenheadLocator",
|
||||
"ground_station_name": "schema:name",
|
||||
"status": "schema:status",
|
||||
"timestamp": "timestamp"
|
||||
}
|
||||
structured_data = []
|
||||
satellite_id_domain = Site.objects.get_current().domain + '/satellite/'
|
||||
|
||||
for frame in data:
|
||||
|
||||
observer_splitted = frame['observer'].split('-')
|
||||
ground_station_locator = observer_splitted.pop()
|
||||
ground_station_name = observer_splitted
|
||||
|
||||
data_to_append = {
|
||||
"frame": frame['frame'],
|
||||
"satellite": {
|
||||
"@id": satellite_id_domain + str(frame['norad_cat_id']),
|
||||
"norad_cat_id": frame['norad_cat_id']
|
||||
},
|
||||
"observer": {
|
||||
"ground_station_name": ground_station_name,
|
||||
"ground_station_locator": ground_station_locator
|
||||
},
|
||||
"timestamp": frame['timestamp']
|
||||
}
|
||||
|
||||
if frame['decoded']:
|
||||
data_to_append['status'] = "decoded"
|
||||
|
||||
structured_data.append(data_to_append)
|
||||
self.data = structured_data
|
||||
|
||||
|
||||
def get_structured_data(basename, data):
|
||||
"""Return structered data instance based on the given basename and given data"""
|
||||
if basename == "mode":
|
||||
return ModeStructuredData(data)
|
||||
if basename == "satellite":
|
||||
return SatelliteStructuredData(data)
|
||||
if basename == "transmitter":
|
||||
return TransmitterStructuredData(data)
|
||||
if basename == "demoddata":
|
||||
return DemodDataStructuredData(data)
|
||||
return None
|
Loading…
Reference in New Issue