From 83f9b07e218be2cc682af0d69e8893ea60600223 Mon Sep 17 00:00:00 2001 From: Corey Shields Date: Mon, 28 Dec 2020 11:39:26 -0500 Subject: [PATCH] Updates for newer API / django rest framework Update to Django Rest Framework 3.12.2 with improved schema generation. However, it is still not quite complete for what we need (and what we currently postprocess for). Instead of postprocessing, this commit introduces our own extended generator to add the missing fields. Once this is vetted good, we can remove contrib/postprocess-openapi-schema.py Also added better comments to api/views.py which will end up in schema docs Signed-off-by: Corey Shields --- .gitlab-ci.yml | 8 ++------ db/api/generators.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ db/api/views.py | 33 ++++++++++++++++++++++++------- requirements-dev.txt | 8 ++++---- requirements.txt | 18 ++++++++--------- setup.cfg | 4 ++-- 6 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 db/api/generators.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5607dba..3348347 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,12 +28,8 @@ schema: - >- ./manage.py generateschema --title "SatNOGS DB" - --description "SatNOGS DB is a transmitter suggestions and crowd-sourcing app." | - ./contrib/postprocess-openapi-schema.py - --expand-aliases - --api-version '1' - --server-url 'https://db.satnogs.org' - --enable-apikey-auth - + --description "SatNOGS DB is a transmitter suggestions and crowd-sourcing app." + --generator_class "db.api.generators.SchemaGenerator" > satnogs-db-api-client/api-schema.yml artifacts: expire_in: 1 week diff --git a/db/api/generators.py b/db/api/generators.py new file mode 100644 index 0000000..dda14ee --- /dev/null +++ b/db/api/generators.py @@ -0,0 +1,46 @@ +""" +NOTE this is a patch to add missing functionality from DRF's openapi implementation +and should be revisited periodically as new functionality is implemented upstream. +refer to https://github.com/encode/django-rest-framework/pull/7516 +""" + +from rest_framework.schemas.openapi import SchemaGenerator as OpenAPISchemaGenerator + + +class SchemaGenerator(OpenAPISchemaGenerator): + """ + Returns an extended schema that includes some missing fields from the + upstream OpenAPI implementation + """ + def get_schema(self, request=None, public=False): + schema = super().get_schema(request, public) + + schema['info']['version'] = '1.0' + + # temporarily add servers until the following is fixed + # https://github.com/encode/django-rest-framework/issues/7631 + schema['servers'] = [ + { + 'url': 'http://localhost:8000', + 'description': 'local dev' + }, { + 'url': 'https://db.satnogs.org', + 'description': 'production' + } + ] + + # temporarily add securitySchemes until implemented upstream + if 'securitySchemes' not in schema['components']: + schema['components']['securitySchemes'] = { + 'ApiKeyAuth': { + 'type': 'apiKey', + 'in': 'header', + 'name': 'Authorization' + } + } + + # temporarily add default security object at top-level + if 'security' not in schema: + schema['security'] = [{'ApiKeyAuth': []}] + + return schema diff --git a/db/api/views.py b/db/api/views.py index 8850748..5757cc7 100644 --- a/db/api/views.py +++ b/db/api/views.py @@ -17,7 +17,7 @@ from db.base.tasks import update_satellite class ModeView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 - """SatNOGS DB Mode API view class""" + """View into the transmitter modulation modes in the SatNOGS DB database""" renderer_classes = [ JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer, BrowserableJSONLDRenderer ] @@ -26,7 +26,7 @@ class ModeView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 class SatelliteView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 - """SatNOGS DB Satellite API view class""" + """View into the Satellite entities in the SatNOGS DB database""" renderer_classes = [ JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer, BrowserableJSONLDRenderer ] @@ -37,7 +37,10 @@ class SatelliteView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 class TransmitterView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 - """SatNOGS DB Transmitter API view class""" + """ + View into the Transmitter entities in the SatNOGS DB database. + Transmitters are inclusive of Transceivers and Transponders + """ renderer_classes = [ JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer, BrowserableJSONLDRenderer ] @@ -48,7 +51,9 @@ class TransmitterView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 class LatestTleSetView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 - """SatNOGS DB Tle API view class""" + """ + View into the most recent two-line elements (TLE) in the SatNOGS DB database + """ renderer_classes = [JSONRenderer, BrowsableAPIRenderer] queryset = LatestTleSet.objects.all().select_related('satellite').exclude( latest_distributable__isnull=True @@ -82,7 +87,11 @@ class LatestTleSetView(viewsets.ReadOnlyModelViewSet): # pylint: disable=R0901 class TelemetryView( # pylint: disable=R0901 mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet): - """SatNOGS DB Telemetry API view class""" + """ + View into the Telemetry objects in the SatNOGS DB database. Currently, + this table is inclusive of all data collected from satellite downlink + observations + """ renderer_classes = [ JSONRenderer, BrowsableAPIRenderer, JSONLDRenderer, BrowserableJSONLDRenderer ] @@ -94,6 +103,11 @@ class TelemetryView( # pylint: disable=R0901 pagination_class = pagination.LinkedHeaderPageNumberPagination def create(self, request, *args, **kwargs): + """ + Creates an frame of telemetry data from a satellite observation. See + https://www.pe0sat.vgnet.nl/download/Hidden/Dombrovski-SIDS-Simple-Downlink-Share-Convention.pdf + for a description of the original protocol. + """ data = {} norad_cat_id = request.data.get('noradID') @@ -149,7 +163,9 @@ class TelemetryView( # pylint: disable=R0901 class ArtifactView( # pylint: disable=R0901 mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet): - """SatNOGS DB Artifact API view class""" + """ + Artifacts are objects collected in relation to a satellite observation. + """ queryset = Artifact.objects.all() filterset_class = filters.ArtifactViewFilter permission_classes = [IsAuthenticated] @@ -163,7 +179,10 @@ class ArtifactView( # pylint: disable=R0901 return serializers.ArtifactSerializer def create(self, request, *args, **kwargs): - """Creates artifact""" + """ + Creates observation artifact + * Requires session or key authentication to create an artifact + """ serializer = self.get_serializer(data=request.data) try: if serializer.is_valid(): diff --git a/requirements-dev.txt b/requirements-dev.txt index 3b4839b..538f11b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,6 +4,7 @@ # './contrib/refresh-requirements.sh to regenerate this file -r requirements.txt +Faker==4.1.8 apipkg==1.5 appdirs==1.4.4 click==7.1.2 @@ -13,21 +14,20 @@ docopt==0.6.1 docopts==0.6.1 execnet==1.7.1 factory-boy==2.12.0 -Faker==4.1.8 filelock==3.0.12 iniconfig==1.1.1 mock==4.0.2 -packaging==20.4 +packaging==20.7 pluggy==0.13.1 pur==5.3.0 py==1.9.0 pyparsing==2.4.7 -pytest==6.1.2 pytest-cov==2.10.1 pytest-django==3.9.0 pytest-forked==1.2.0 pytest-xdist==1.33.0 +pytest==6.1.2 text-unidecode==1.3 toml==0.10.2 tox==3.16.0 -virtualenv==20.1.0 +virtualenv==20.2.1 diff --git a/requirements.txt b/requirements.txt index 5e13a96..48b145d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ billiard==3.6.3.0 cachetools==4.1.1 celery==4.4.7 certifi==2020.11.8 -cffi==1.14.3 +cffi==1.14.4 chardet==3.0.4 cryptography==3.2.1 defusedxml==0.7.0rc1 @@ -18,7 +18,7 @@ Django==2.2.17 django-allauth==0.42.0 django-appconf==1.0.4 django-avatar==5.0.0 -django-bootstrap-modal-forms==2.0.0 +django-bootstrap-modal-forms==2.0.1 django-compressor==2.4 django-countries==6.1.3 django-crispy-forms==1.9.2 @@ -30,23 +30,23 @@ django-jsonfield==1.3.1 django-redis-cache==2.0.0 django-shortuuidfield==0.1.3 django-widget-tweaks==1.4.8 -djangorestframework==3.11.2 +djangorestframework==3.12.2 dnspython==1.16.0 enum34==1.1.10 eventlet==0.29.1 frozendict==1.2 greenlet==0.4.17 gunicorn==19.9.0 -h5py==2.10.0 +h5py==3.1.0 idna==2.10 importlib-metadata==1.7.0 -influxdb==5.3.0 +influxdb==5.3.1 kaitaistruct==0.9 kombu==4.6.11 Logbook==1.5.3 -lxml==4.6.1 +lxml==4.6.2 Markdown==3.2.2 -msgpack==0.6.1 +msgpack==1.0.0 mysqlclient==2.0.1 numpy==1.19.4 oauthlib==3.1.0 @@ -63,7 +63,7 @@ PyYAML==5.3.1 rcssmin==1.0.6 redis==3.5.3 Represent==1.6.0 -requests==2.24.0 +requests==2.25.0 requests-oauthlib==1.3.0 rjsmin==1.1.0 rush==2018.12.1 @@ -80,6 +80,6 @@ spacetrack==0.15.0 sqlparse==0.4.1 Unipath==1.1 uritemplate==3.0.1 -urllib3==1.25.11 +urllib3==1.26.2 vine==1.3.0 zipp==3.4.0 diff --git a/setup.cfg b/setup.cfg index 6d3eba3..e6c267e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,7 +51,7 @@ install_requires = # Static django_compressor~=2.4.0 # API - djangorestframework~=3.11.0 + djangorestframework~=3.12.0 Markdown~=3.2.0 django-filter~=2.3.0 # Astronomy @@ -66,7 +66,7 @@ install_requires = simplejson~=3.17.0 uritemplate~=3.0.0 PyYAML~=5.3.0 - h5py~=2.10.0 + h5py~=3.1.0 PyLD~=2.0.2 # Metasat django-countries~=6.1.2