Add JSON-LD post API endpoint for Transmitter suggestions
Signed-off-by: Alfredos-Panagiotis Damkalis <fredy@fredy.gr>spacecruft
parent
4141e275cc
commit
804b69e442
|
@ -0,0 +1,18 @@
|
|||
"""SatNOGS DB django rest framework API custom parsers"""
|
||||
from pyld import jsonld
|
||||
from rest_framework.parsers import JSONParser
|
||||
|
||||
from db.base.structured_data import get_structured_data
|
||||
|
||||
|
||||
class JSONLDParser(JSONParser): # pylint: disable=R0903
|
||||
""" Parser for JSONLD. """
|
||||
|
||||
media_type = 'application/ld+json'
|
||||
|
||||
def parse(self, stream, media_type=None, parser_context=None):
|
||||
""" Render `data` into JSONLD, returning a bytestring. """
|
||||
raw_data = super().parse(stream, media_type, parser_context)
|
||||
structured_data = get_structured_data(parser_context['view'].basename, [])
|
||||
data = jsonld.frame(raw_data, structured_data.frame, {'omitGraph': False})
|
||||
return data
|
|
@ -8,7 +8,7 @@ from drf_spectacular.utils import OpenApiExample, extend_schema_field, extend_sc
|
|||
from rest_framework import serializers
|
||||
|
||||
from db.base.models import TRANSMITTER_STATUS, Artifact, DemodData, LatestTleSet, Mode, \
|
||||
Satellite, Telemetry, Transmitter
|
||||
Satellite, Telemetry, Transmitter, TransmitterEntry
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
|
@ -181,6 +181,18 @@ class SatelliteSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class TransmitterEntrySerializer(serializers.ModelSerializer):
|
||||
"""SatNOGS DB TransmitterEntry API Serializer"""
|
||||
class Meta:
|
||||
model = TransmitterEntry
|
||||
fields = (
|
||||
'uuid', 'description', 'status', 'type', 'uplink_low', 'uplink_high', 'uplink_drift',
|
||||
'downlink_low', 'downlink_high', 'downlink_drift', 'downlink_mode', 'uplink_mode',
|
||||
'invert', 'baud', 'satellite', 'citation', 'service', 'coordination',
|
||||
'coordination_url', 'created_by'
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_serializer(
|
||||
examples=[
|
||||
OpenApiExample(
|
||||
|
|
172
db/api/views.py
172
db/api/views.py
|
@ -15,6 +15,7 @@ from rest_framework.response import Response
|
|||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from db.api import filters, pagination, serializers
|
||||
from db.api.parsers import JSONLDParser
|
||||
from db.api.perms import SafeMethodsWithPermission
|
||||
from db.api.renderers import BrowserableJSONLDRenderer, JSONLDRenderer
|
||||
from db.base.helpers import gridsquare
|
||||
|
@ -152,14 +153,17 @@ class SatelliteViewSet(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
|||
],
|
||||
),
|
||||
)
|
||||
class TransmitterViewSet(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
||||
class TransmitterViewSet( # pylint: disable=R0901
|
||||
mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin,
|
||||
viewsets.GenericViewSet):
|
||||
"""
|
||||
Read-only view into the Transmitter entities in the SatNOGS DB database.
|
||||
View into the Transmitter entities in the SatNOGS DB database.
|
||||
Transmitters are inclusive of Transceivers and Transponders
|
||||
"""
|
||||
renderer_classes = [
|
||||
JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer, BrowserableJSONLDRenderer
|
||||
]
|
||||
parser_classes = [JSONLDParser]
|
||||
queryset = Transmitter.objects.filter(
|
||||
satellite__associated_satellite__isnull=True, satellite__satellite_entry__approved=True
|
||||
)
|
||||
|
@ -167,6 +171,170 @@ class TransmitterViewSet(viewsets.ReadOnlyModelViewSet): # pylint: disable=R090
|
|||
filterset_class = filters.TransmitterViewFilter
|
||||
lookup_field = 'uuid'
|
||||
|
||||
def create(self, request, *args, **kwargs): # noqa: C901; pylint: disable=R0911,R0912,R0915
|
||||
"""
|
||||
Creates a transmitter suggestion.
|
||||
"""
|
||||
transmitters_data = []
|
||||
for transmitter_entry in request.data['@graph']:
|
||||
if 'transmitter' not in transmitter_entry:
|
||||
data = 'Transmitter Entry without "transmitter" key'
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if not transmitter_entry['transmitter']:
|
||||
data = 'One or more of the required fields are missing.\n Required fields: \
|
||||
description, status, citation, service, satellite'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
transmitter = transmitter_entry['transmitter']
|
||||
|
||||
transmitter_data = {}
|
||||
if "@id" not in transmitter:
|
||||
data = 'Missing "@id" for one or more entries'
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if 'uuid' in transmitter:
|
||||
if isinstance(transmitter['uuid'], list):
|
||||
data = 'Multiple values for "http://schema.org/identifier" or multiple \
|
||||
entries with the same "@id" and different \
|
||||
"http://schema.org/identifier" values'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
transmitter_uuid = transmitter['uuid']
|
||||
if Transmitter.objects.filter(uuid=transmitter_uuid).exists():
|
||||
transmitter_data['uuid'] = transmitter_uuid
|
||||
|
||||
transmitter_data['description'] = transmitter['description']
|
||||
transmitter_data['status'] = transmitter['status']
|
||||
transmitter_data['citation'] = transmitter['citation']
|
||||
transmitter_data['service'] = transmitter['service']
|
||||
transmitter_data['coordination'] = ''
|
||||
transmitter_data['coordination_url'] = ''
|
||||
transmitter_data['created_by'] = request.user.pk
|
||||
|
||||
try:
|
||||
if transmitter['satellite']:
|
||||
if isinstance(transmitter['satellite'], list):
|
||||
data = 'Multiple values for "https://schema.space/metasat/satellite" \
|
||||
or multiple entries with the same "@id" and different \
|
||||
"https://schema.space/metasat/satellite" values'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
transmitter_data['satellite'] = Satellite.objects.get(
|
||||
satellite_entry__norad_cat_id=transmitter['satellite']['norad_cat_id']
|
||||
).pk
|
||||
else:
|
||||
data = 'Missing NORAD ID value for Satellite'
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
except Satellite.DoesNotExist:
|
||||
data = 'Unknown NORAD ID: {}'.format(transmitter['satellite']['norad_cat_id'])
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if 'baud' in transmitter:
|
||||
transmitter_data['baud'] = transmitter['baud']
|
||||
|
||||
if 'invert' in transmitter:
|
||||
transmitter_data['invert'] = transmitter['invert']
|
||||
|
||||
if 'uplink' not in transmitter and 'downlink' not in transmitter:
|
||||
data = 'Missing "https://schema.space/metasat/uplink" or \
|
||||
"https://schema.space/metasat/downlink"'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if 'uplink' in transmitter:
|
||||
if isinstance(transmitter['uplink'], list):
|
||||
data = 'Multiple values for "https://schema.space/metasat/uplink" or multiple \
|
||||
entries with the same "@id" and different \
|
||||
"https://schema.space/metasat/uplink" values'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if 'frequency' not in transmitter['uplink']:
|
||||
data = 'Missing "https://schema.space/metasat/frequency" from \
|
||||
"https://schema.space/metasat/uplink" value'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if isinstance(transmitter['uplink']['frequency'], int):
|
||||
transmitter_data['type'] = 'Transceiver'
|
||||
transmitter_data['uplink_low'] = transmitter['uplink']['frequency']
|
||||
else:
|
||||
transmitter_data['type'] = 'Transponder'
|
||||
if 'minimum' not in transmitter['uplink'][
|
||||
'frequency'] or 'maximum' not in transmitter['uplink']['frequency']:
|
||||
data = 'Missing "https://schema.org/minimum" or \
|
||||
"https://schema.org/maximum" from \
|
||||
"https://schema.space/metasat/frequency" value of \
|
||||
"https://schema.space/metasat/uplink"'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
transmitter_data['uplink_low'] = transmitter['uplink']['frequency']['minimum']
|
||||
transmitter_data['uplink_high'] = transmitter['uplink']['frequency']['maximum']
|
||||
if 'mode' in transmitter['uplink']:
|
||||
try:
|
||||
transmitter_data['uplink_mode'] = Mode.objects.get(
|
||||
name=transmitter['uplink']['mode']
|
||||
).pk
|
||||
except Mode.DoesNotExist:
|
||||
data = 'Unknown Mode: {}'.format(transmitter['uplink']['mode'])
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if 'drift' in transmitter['uplink']:
|
||||
transmitter_data['uplink_drift'] = transmitter['uplink']['drift']
|
||||
else:
|
||||
transmitter_data['type'] = 'Transmitter'
|
||||
|
||||
if 'downlink' in transmitter:
|
||||
if isinstance(transmitter['downlink'], list):
|
||||
data = 'Multiple values for "https://schema.space/metasat/downlink" or \
|
||||
multiple entries with the same "@id" and different \
|
||||
"https://schema.space/metasat/downlink" values'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if 'frequency' not in transmitter['downlink']:
|
||||
data = 'Missing "https://schema.space/metasat/frequency" from \
|
||||
"https://schema.space/metasat/downlink" value'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if isinstance(transmitter['downlink']['frequency'],
|
||||
int) and not transmitter_data['type'] == 'Transponder':
|
||||
transmitter_data['downlink_low'] = transmitter['downlink']['frequency']
|
||||
elif transmitter_data['type'] == 'Transponder':
|
||||
if 'minimum' not in transmitter['downlink'][
|
||||
'frequency'] or 'maximum' not in transmitter['downlink']['frequency']:
|
||||
data = 'Missing "https://schema.org/minimum" or \
|
||||
"https://schema.org/maximum" from \
|
||||
"https://schema.space/metasat/frequency" value of \
|
||||
"https://schema.space/metasat/downlink"'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
transmitter_data['downlink_low'] = transmitter['downlink']['frequency'][
|
||||
'minimum']
|
||||
transmitter_data['downlink_high'] = transmitter['downlink']['frequency'][
|
||||
'maximum']
|
||||
else:
|
||||
data = 'Expected integer for "https://schema.space/metasat/frequency" value \
|
||||
of "https://schema.space/metasat/downlink"'
|
||||
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if 'mode' in transmitter['downlink']:
|
||||
try:
|
||||
transmitter_data['downlink_mode'] = Mode.objects.get(
|
||||
name=transmitter['downlink']['mode']
|
||||
).pk
|
||||
except Mode.DoesNotExist:
|
||||
data = 'Unknown Mode: {}'.format(transmitter['downlink']['mode'])
|
||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if 'drift' in transmitter['downlink']:
|
||||
transmitter_data['downlink_drift'] = transmitter['downlink']['drift']
|
||||
transmitters_data.append(transmitter_data)
|
||||
|
||||
serializer = serializers.TransmitterEntrySerializer(
|
||||
data=transmitters_data, many=True, allow_empty=True
|
||||
)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
else:
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response(status=status.HTTP_201_CREATED)
|
||||
|
||||
|
||||
class LatestTleSetViewSet(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901
|
||||
"""
|
||||
|
|
|
@ -131,6 +131,20 @@ class TransmitterStructuredData(StructuredData):
|
|||
"citation": "schema:citation",
|
||||
"service": "service"
|
||||
}
|
||||
self.frame = {
|
||||
"@context": self.context,
|
||||
'transmitter': {
|
||||
"@requireAll": True,
|
||||
"description": {},
|
||||
"status": {},
|
||||
"citation": {},
|
||||
"service": {},
|
||||
"satellite": {
|
||||
"@requireAll": True,
|
||||
"norad_cat_id": {}
|
||||
},
|
||||
}
|
||||
}
|
||||
structured_data = []
|
||||
transmitter_id_domain = Site.objects.get_current().domain + '/transmitter/'
|
||||
satellite_id_domain = Site.objects.get_current().domain + '/satellite/'
|
||||
|
|
Loading…
Reference in New Issue