pylint C0111 docstrings
phew, fixed all of the missing-docstring and found some other things along the way (for future changes)merge-requests/398/head
parent
dcccb1770e
commit
2ec2fd2a4d
|
@ -4,7 +4,6 @@ load-plugins=pylint_django
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
disable=
|
disable=
|
||||||
C0111,
|
|
||||||
C0411,
|
C0411,
|
||||||
C0412,
|
C0412,
|
||||||
E1101,
|
E1101,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""SatNOGS DB Auth0 login module admin class"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# from django.contrib import admin
|
# from django.contrib import admin
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""SatNOGS DB Auth0 login app config"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class Auth0LoginConfig(AppConfig):
|
class Auth0LoginConfig(AppConfig):
|
||||||
|
"""Set the name of the django app for auth0login"""
|
||||||
name = 'auth0login'
|
name = 'auth0login'
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB Auth0 login module auth backend"""
|
||||||
import requests
|
import requests
|
||||||
from social_core.backends.oauth import BaseOAuth2
|
from social_core.backends.oauth import BaseOAuth2
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""SatNOGS DB Auth0 login module models"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# from django.db import models
|
# from django.db import models
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""SatNOGS DB Auth0 login module test suites"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# from django.test import TestCase
|
# from django.test import TestCase
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB Auth0 login module URL routers"""
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
"""SatNOGS DB Auth0 login module views"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
|
"""Returns the index view"""
|
||||||
return render(request, 'index.html')
|
return render(request, 'index.html')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""The core django app for SatNOGS DB"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from ._version import get_versions
|
from ._version import get_versions
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django rest framework Filters class"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -9,9 +10,11 @@ from db.base.models import DemodData, Satellite, Transmitter
|
||||||
|
|
||||||
|
|
||||||
class TransmitterViewFilter(FilterSet):
|
class TransmitterViewFilter(FilterSet):
|
||||||
|
"""SatNOGS DB Transmitter API View Filter"""
|
||||||
alive = filters.BooleanFilter(field_name='status', label='Alive', method='filter_status')
|
alive = filters.BooleanFilter(field_name='status', label='Alive', method='filter_status')
|
||||||
|
|
||||||
def filter_status(self, queryset, name, value):
|
def filter_status(self, queryset, name, value):
|
||||||
|
"""Returns Transmitters that are either functional or non-functional"""
|
||||||
if value:
|
if value:
|
||||||
return queryset.filter(status='functional')
|
return queryset.filter(status='functional')
|
||||||
else:
|
else:
|
||||||
|
@ -23,7 +26,10 @@ class TransmitterViewFilter(FilterSet):
|
||||||
|
|
||||||
|
|
||||||
class SatelliteViewFilter(FilterSet):
|
class SatelliteViewFilter(FilterSet):
|
||||||
''' filter on decayed field '''
|
"""SatNOGS DB Satellite API View Filter
|
||||||
|
|
||||||
|
filter on decayed field
|
||||||
|
"""
|
||||||
in_orbit = filters.BooleanFilter(field_name='decayed', label='In orbit', lookup_expr='isnull')
|
in_orbit = filters.BooleanFilter(field_name='decayed', label='In orbit', lookup_expr='isnull')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -32,6 +38,7 @@ class SatelliteViewFilter(FilterSet):
|
||||||
|
|
||||||
|
|
||||||
class TelemetryViewFilter(FilterSet):
|
class TelemetryViewFilter(FilterSet):
|
||||||
|
"""SatNOGS DB Telemetry API View Filter"""
|
||||||
satellite = django_filters.NumberFilter(
|
satellite = django_filters.NumberFilter(
|
||||||
field_name='satellite__norad_cat_id', lookup_expr='exact'
|
field_name='satellite__norad_cat_id', lookup_expr='exact'
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB API serializers, django rest framework"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -8,18 +9,21 @@ from db.base.models import TRANSMITTER_STATUS, DemodData, Mode, Satellite, \
|
||||||
|
|
||||||
|
|
||||||
class ModeSerializer(serializers.ModelSerializer):
|
class ModeSerializer(serializers.ModelSerializer):
|
||||||
|
"""SatNOGS DB Mode API Serializer"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Mode
|
model = Mode
|
||||||
fields = ('id', 'name')
|
fields = ('id', 'name')
|
||||||
|
|
||||||
|
|
||||||
class SatelliteSerializer(serializers.ModelSerializer):
|
class SatelliteSerializer(serializers.ModelSerializer):
|
||||||
|
"""SatNOGS DB Satellite API Serializer"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Satellite
|
model = Satellite
|
||||||
fields = ('norad_cat_id', 'name', 'names', 'image', 'status', 'decayed')
|
fields = ('norad_cat_id', 'name', 'names', 'image', 'status', 'decayed')
|
||||||
|
|
||||||
|
|
||||||
class TransmitterSerializer(serializers.ModelSerializer):
|
class TransmitterSerializer(serializers.ModelSerializer):
|
||||||
|
"""SatNOGS DB Transmitter API Serializer"""
|
||||||
norad_cat_id = serializers.SerializerMethodField()
|
norad_cat_id = serializers.SerializerMethodField()
|
||||||
mode_id = serializers.SerializerMethodField()
|
mode_id = serializers.SerializerMethodField()
|
||||||
mode = serializers.SerializerMethodField()
|
mode = serializers.SerializerMethodField()
|
||||||
|
@ -36,25 +40,30 @@ class TransmitterSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
# Keeping alive field for compatibility issues
|
# Keeping alive field for compatibility issues
|
||||||
def get_alive(self, obj):
|
def get_alive(self, obj):
|
||||||
|
"""Returns transmitter status"""
|
||||||
return obj.status == TRANSMITTER_STATUS[0]
|
return obj.status == TRANSMITTER_STATUS[0]
|
||||||
|
|
||||||
def get_mode_id(self, obj):
|
def get_mode_id(self, obj):
|
||||||
|
"""Returns mode ID"""
|
||||||
try:
|
try:
|
||||||
return obj.mode.id
|
return obj.mode.id
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_mode(self, obj):
|
def get_mode(self, obj):
|
||||||
|
"""Returns mode name"""
|
||||||
try:
|
try:
|
||||||
return obj.mode.name
|
return obj.mode.name
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_norad_cat_id(self, obj):
|
def get_norad_cat_id(self, obj):
|
||||||
|
"""Returns Satellite NORAD ID"""
|
||||||
return obj.satellite.norad_cat_id
|
return obj.satellite.norad_cat_id
|
||||||
|
|
||||||
|
|
||||||
class TelemetrySerializer(serializers.ModelSerializer):
|
class TelemetrySerializer(serializers.ModelSerializer):
|
||||||
|
"""SatNOGS DB Telemetry API Serializer"""
|
||||||
norad_cat_id = serializers.SerializerMethodField()
|
norad_cat_id = serializers.SerializerMethodField()
|
||||||
transmitter = serializers.SerializerMethodField()
|
transmitter = serializers.SerializerMethodField()
|
||||||
schema = serializers.SerializerMethodField()
|
schema = serializers.SerializerMethodField()
|
||||||
|
@ -69,28 +78,36 @@ class TelemetrySerializer(serializers.ModelSerializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_norad_cat_id(self, obj):
|
def get_norad_cat_id(self, obj):
|
||||||
|
"""Returns Satellite NORAD ID for this Transmitter"""
|
||||||
return obj.satellite.norad_cat_id
|
return obj.satellite.norad_cat_id
|
||||||
|
|
||||||
def get_transmitter(self, obj):
|
def get_transmitter(self, obj):
|
||||||
|
"""Returns Transmitter UUID"""
|
||||||
try:
|
try:
|
||||||
return obj.transmitter.uuid
|
return obj.transmitter.uuid
|
||||||
except Exception:
|
except Exception:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
# TODO: this is a relic of the old data decoding method, needs revisiting
|
||||||
def get_schema(self, obj):
|
def get_schema(self, obj):
|
||||||
|
"""Returns Transmitter telemetry schema"""
|
||||||
try:
|
try:
|
||||||
return obj.payload_telemetry.schema
|
return obj.payload_telemetry.schema
|
||||||
except Exception:
|
except Exception:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
# TODO: this is a relic of the old data decoding method, needs revisiting
|
||||||
def get_decoded(self, obj):
|
def get_decoded(self, obj):
|
||||||
|
"""Returns the payload_decoded field"""
|
||||||
return obj.payload_decoded
|
return obj.payload_decoded
|
||||||
|
|
||||||
def get_frame(self, obj):
|
def get_frame(self, obj):
|
||||||
|
"""Returns the payload frame"""
|
||||||
return obj.display_frame()
|
return obj.display_frame()
|
||||||
|
|
||||||
|
|
||||||
class SidsSerializer(serializers.ModelSerializer):
|
class SidsSerializer(serializers.ModelSerializer):
|
||||||
|
"""SatNOGS DB SiDS API Serializer"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DemodData
|
model = DemodData
|
||||||
fields = ('satellite', 'payload_frame', 'station', 'lat', 'lng', 'timestamp', 'app_source')
|
fields = ('satellite', 'payload_frame', 'station', 'lat', 'lng', 'timestamp', 'app_source')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB API test suites"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -21,10 +22,12 @@ class ModeViewApiTest(TestCase):
|
||||||
self.mode.save()
|
self.mode.save()
|
||||||
|
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
|
"""Test the API modes list"""
|
||||||
response = self.client.get('/api/modes/', format='json')
|
response = self.client.get('/api/modes/', format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_retrieve(self):
|
def test_retrieve(self):
|
||||||
|
"""Test the API mode retrieval"""
|
||||||
response = self.client.get('/api/modes/{0}/'.format(self.mode.id), format='json')
|
response = self.client.get('/api/modes/{0}/'.format(self.mode.id), format='json')
|
||||||
self.assertContains(response, self.mode.name)
|
self.assertContains(response, self.mode.name)
|
||||||
|
|
||||||
|
@ -41,10 +44,12 @@ class SatelliteViewApiTest(TestCase):
|
||||||
self.satellite.save()
|
self.satellite.save()
|
||||||
|
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
|
"""Test the Satellite API listing"""
|
||||||
response = self.client.get('/api/satellites/', format='json')
|
response = self.client.get('/api/satellites/', format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_retrieve(self):
|
def test_retrieve(self):
|
||||||
|
"""Test the Satellite API retrieval"""
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
'/api/satellites/{0}/'.format(self.satellite.norad_cat_id), format='json'
|
'/api/satellites/{0}/'.format(self.satellite.norad_cat_id), format='json'
|
||||||
)
|
)
|
||||||
|
@ -64,10 +69,12 @@ class TransmitterViewApiTest(TestCase):
|
||||||
self.transmitter.save()
|
self.transmitter.save()
|
||||||
|
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
|
"""Test the Transmitter API listing"""
|
||||||
response = self.client.get('/api/transmitters/', format='json')
|
response = self.client.get('/api/transmitters/', format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_retrieve(self):
|
def test_retrieve(self):
|
||||||
|
"""Test the Transmitter API retrieval"""
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
'/api/transmitters/{0}/'.format(self.transmitter.uuid), format='json'
|
'/api/transmitters/{0}/'.format(self.transmitter.uuid), format='json'
|
||||||
)
|
)
|
||||||
|
@ -86,9 +93,11 @@ class TelemetryViewApiTest(TestCase):
|
||||||
self.datum.save()
|
self.datum.save()
|
||||||
|
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
|
"""Test the Telemetry API listing"""
|
||||||
response = self.client.get('/api/telemetry/', format='json')
|
response = self.client.get('/api/telemetry/', format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_retrieve(self):
|
def test_retrieve(self):
|
||||||
|
"""Test the Telemetry API retrieval"""
|
||||||
response = self.client.get('/api/telemetry/{0}/'.format(self.datum.id), format='json')
|
response = self.client.get('/api/telemetry/{0}/'.format(self.datum.id), format='json')
|
||||||
self.assertContains(response, self.datum.observer)
|
self.assertContains(response, self.datum.observer)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django rest framework API url routings"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB API django rest framework Views"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -13,11 +14,13 @@ from db.base.tasks import update_satellite
|
||||||
|
|
||||||
|
|
||||||
class ModeView(viewsets.ReadOnlyModelViewSet):
|
class ModeView(viewsets.ReadOnlyModelViewSet):
|
||||||
|
"""SatNOGS DB Mode API view class"""
|
||||||
queryset = Mode.objects.all()
|
queryset = Mode.objects.all()
|
||||||
serializer_class = serializers.ModeSerializer
|
serializer_class = serializers.ModeSerializer
|
||||||
|
|
||||||
|
|
||||||
class SatelliteView(viewsets.ReadOnlyModelViewSet):
|
class SatelliteView(viewsets.ReadOnlyModelViewSet):
|
||||||
|
"""SatNOGS DB Satellite API view class"""
|
||||||
queryset = Satellite.objects.all()
|
queryset = Satellite.objects.all()
|
||||||
serializer_class = serializers.SatelliteSerializer
|
serializer_class = serializers.SatelliteSerializer
|
||||||
filter_class = filters.SatelliteViewFilter
|
filter_class = filters.SatelliteViewFilter
|
||||||
|
@ -25,6 +28,7 @@ class SatelliteView(viewsets.ReadOnlyModelViewSet):
|
||||||
|
|
||||||
|
|
||||||
class TransmitterView(viewsets.ReadOnlyModelViewSet):
|
class TransmitterView(viewsets.ReadOnlyModelViewSet):
|
||||||
|
"""SatNOGS DB Transmitter API view class"""
|
||||||
queryset = Transmitter.objects.all()
|
queryset = Transmitter.objects.all()
|
||||||
serializer_class = serializers.TransmitterSerializer
|
serializer_class = serializers.TransmitterSerializer
|
||||||
filter_class = filters.TransmitterViewFilter
|
filter_class = filters.TransmitterViewFilter
|
||||||
|
@ -33,6 +37,7 @@ class TransmitterView(viewsets.ReadOnlyModelViewSet):
|
||||||
|
|
||||||
class TelemetryView(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin,
|
class TelemetryView(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin,
|
||||||
viewsets.GenericViewSet):
|
viewsets.GenericViewSet):
|
||||||
|
"""SatNOGS DB Telemetry API view class"""
|
||||||
queryset = DemodData.objects.all()
|
queryset = DemodData.objects.all()
|
||||||
serializer_class = serializers.TelemetrySerializer
|
serializer_class = serializers.TelemetrySerializer
|
||||||
filter_class = filters.TelemetryViewFilter
|
filter_class = filters.TelemetryViewFilter
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Defines functions and settings for the django admin interface"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -17,16 +18,25 @@ from db.base.tasks import check_celery, decode_all_data
|
||||||
|
|
||||||
@admin.register(Mode)
|
@admin.register(Mode)
|
||||||
class ModeAdmin(admin.ModelAdmin):
|
class ModeAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines Mode view in django admin UI"""
|
||||||
list_display = ('name', )
|
list_display = ('name', )
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Satellite)
|
@admin.register(Satellite)
|
||||||
class SatelliteAdmin(admin.ModelAdmin):
|
class SatelliteAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines Satellite view in django admin UI"""
|
||||||
list_display = ('name', 'norad_cat_id', 'status', 'decayed')
|
list_display = ('name', 'norad_cat_id', 'status', 'decayed')
|
||||||
search_fields = ('name', 'norad_cat_id')
|
search_fields = ('name', 'norad_cat_id')
|
||||||
list_filter = ('status', 'decayed')
|
list_filter = ('status', 'decayed')
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
|
"""Returns django urls for the Satellite view
|
||||||
|
|
||||||
|
check_celery -- url for the check_celery function
|
||||||
|
decode_all_data -- url for the decode_all_data function
|
||||||
|
|
||||||
|
:returns: Django urls for the Satellite admin view
|
||||||
|
"""
|
||||||
urls = super(SatelliteAdmin, self).get_urls()
|
urls = super(SatelliteAdmin, self).get_urls()
|
||||||
my_urls = [
|
my_urls = [
|
||||||
url(r'^check_celery/$', self.check_celery, name='check_celery'),
|
url(r'^check_celery/$', self.check_celery, name='check_celery'),
|
||||||
|
@ -39,6 +49,14 @@ class SatelliteAdmin(admin.ModelAdmin):
|
||||||
return my_urls + urls
|
return my_urls + urls
|
||||||
|
|
||||||
def check_celery(self, request):
|
def check_celery(self, request):
|
||||||
|
"""Returns status of Celery workers
|
||||||
|
|
||||||
|
Check the delay for celery workers, return an error if a connection
|
||||||
|
can not be made or if the delay is too long. Otherwise return that
|
||||||
|
Celery is OK.
|
||||||
|
|
||||||
|
:returns: admin home page redirect with popup message
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
investigator = check_celery.delay()
|
investigator = check_celery.delay()
|
||||||
except socket_error as error:
|
except socket_error as error:
|
||||||
|
@ -54,9 +72,15 @@ class SatelliteAdmin(admin.ModelAdmin):
|
||||||
finally:
|
finally:
|
||||||
return HttpResponseRedirect(reverse('admin:index'))
|
return HttpResponseRedirect(reverse('admin:index'))
|
||||||
|
|
||||||
# force a decode of all data for a norad ID. This could be very resource
|
|
||||||
# intensive but necessary when catching a satellite up with a new decoder
|
|
||||||
def decode_all_data(self, request, norad):
|
def decode_all_data(self, request, norad):
|
||||||
|
"""Returns the admin home page, while triggering a Celery decode task
|
||||||
|
|
||||||
|
Forces a decode of all data for a norad ID. This could be very resource
|
||||||
|
intensive but necessary when catching a satellite up with a new decoder
|
||||||
|
|
||||||
|
:param norad: the NORAD ID for the satellite to decode
|
||||||
|
:returns: Admin home page
|
||||||
|
"""
|
||||||
decode_all_data.delay(norad)
|
decode_all_data.delay(norad)
|
||||||
messages.success(request, 'Decode task was triggered successfully!')
|
messages.success(request, 'Decode task was triggered successfully!')
|
||||||
return redirect(reverse('admin:index'))
|
return redirect(reverse('admin:index'))
|
||||||
|
@ -64,6 +88,7 @@ class SatelliteAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(TransmitterEntry)
|
@admin.register(TransmitterEntry)
|
||||||
class TransmitterEntryAdmin(admin.ModelAdmin):
|
class TransmitterEntryAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines TransmitterEntry view in django admin UI"""
|
||||||
list_display = (
|
list_display = (
|
||||||
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
||||||
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'reviewed',
|
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'reviewed',
|
||||||
|
@ -84,6 +109,7 @@ class TransmitterEntryAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(TransmitterSuggestion)
|
@admin.register(TransmitterSuggestion)
|
||||||
class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines TransmitterSuggestion view in django admin UI"""
|
||||||
list_display = (
|
list_display = (
|
||||||
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
||||||
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
|
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
|
||||||
|
@ -104,6 +130,12 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
||||||
actions = ['approve_suggestion', 'reject_suggestion']
|
actions = ['approve_suggestion', 'reject_suggestion']
|
||||||
|
|
||||||
def get_actions(self, request):
|
def get_actions(self, request):
|
||||||
|
"""Returns the actions a user can take on a TransmitterSuggestion
|
||||||
|
|
||||||
|
For example, delete, approve, or reject
|
||||||
|
|
||||||
|
:returns: list of actions the user can take on TransmitterSuggestion
|
||||||
|
"""
|
||||||
actions = super(TransmitterSuggestionAdmin, self).get_actions(request)
|
actions = super(TransmitterSuggestionAdmin, self).get_actions(request)
|
||||||
if not request.user.has_perm('base.delete_transmittersuggestion'):
|
if not request.user.has_perm('base.delete_transmittersuggestion'):
|
||||||
if 'delete_selected' in actions:
|
if 'delete_selected' in actions:
|
||||||
|
@ -111,6 +143,11 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
def approve_suggestion(self, request, queryset):
|
def approve_suggestion(self, request, queryset):
|
||||||
|
"""Returns the TransmitterSuggestion page after approving suggestions
|
||||||
|
|
||||||
|
:param queryset: the TransmitterSuggestion entries to be approved
|
||||||
|
:returns: TransmitterSuggestion admin page
|
||||||
|
"""
|
||||||
queryset_size = len(queryset)
|
queryset_size = len(queryset)
|
||||||
for entry in queryset:
|
for entry in queryset:
|
||||||
entry.approved = True
|
entry.approved = True
|
||||||
|
@ -129,6 +166,11 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
||||||
approve_suggestion.short_description = 'Approve selected transmitter suggestions'
|
approve_suggestion.short_description = 'Approve selected transmitter suggestions'
|
||||||
|
|
||||||
def reject_suggestion(self, request, queryset):
|
def reject_suggestion(self, request, queryset):
|
||||||
|
"""Returns the TransmitterSuggestion page after rejecting suggestions
|
||||||
|
|
||||||
|
:param queryset: the TransmitterSuggestion entries to be rejected
|
||||||
|
:returns: TransmitterSuggestion admin page
|
||||||
|
"""
|
||||||
queryset_size = len(queryset)
|
queryset_size = len(queryset)
|
||||||
for entry in queryset:
|
for entry in queryset:
|
||||||
entry.created = datetime.utcnow()
|
entry.created = datetime.utcnow()
|
||||||
|
@ -149,6 +191,7 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(Transmitter)
|
@admin.register(Transmitter)
|
||||||
class TransmitterAdmin(admin.ModelAdmin):
|
class TransmitterAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines Transmitter view in django admin UI"""
|
||||||
list_display = (
|
list_display = (
|
||||||
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
|
||||||
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
|
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
|
||||||
|
@ -167,13 +210,20 @@ class TransmitterAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
@admin.register(Telemetry)
|
@admin.register(Telemetry)
|
||||||
class TelemetryAdmin(admin.ModelAdmin):
|
class TelemetryAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines Telemetry view in django admin UI"""
|
||||||
list_display = ('name', 'decoder')
|
list_display = ('name', 'decoder')
|
||||||
|
|
||||||
|
|
||||||
@admin.register(DemodData)
|
@admin.register(DemodData)
|
||||||
class DemodDataAdmin(admin.ModelAdmin):
|
class DemodDataAdmin(admin.ModelAdmin):
|
||||||
|
"""Defines DemodData view in django admin UI"""
|
||||||
list_display = ('id', 'satellite', 'app_source', 'observer')
|
list_display = ('id', 'satellite', 'app_source', 'observer')
|
||||||
search_fields = ('transmitter__uuid', 'satellite__norad_cat_id', 'observer')
|
search_fields = ('transmitter__uuid', 'satellite__norad_cat_id', 'observer')
|
||||||
|
|
||||||
def satellite(self, obj):
|
def satellite(self, obj):
|
||||||
|
"""Returns the Satellite object associated with this DemodData
|
||||||
|
|
||||||
|
:param obj: DemodData object
|
||||||
|
:returns: Satellite object
|
||||||
|
"""
|
||||||
return obj.satellite
|
return obj.satellite
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django context processors"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django base Forms class"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -9,7 +10,9 @@ from db.base.models import Transmitter, TransmitterEntry
|
||||||
|
|
||||||
|
|
||||||
class TransmitterEntryForm(forms.ModelForm):
|
class TransmitterEntryForm(forms.ModelForm):
|
||||||
|
"""Model Form class for TransmitterEntry objects"""
|
||||||
def existing_uuid(value):
|
def existing_uuid(value):
|
||||||
|
"""ensures the UUID is existing and valid"""
|
||||||
try:
|
try:
|
||||||
Transmitter.objects.get(uuid=value)
|
Transmitter.objects.get(uuid=value)
|
||||||
except Transmitter.DoesNotExist:
|
except Transmitter.DoesNotExist:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Helper functions for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -9,6 +10,13 @@ LOWER = 'abcdefghijklmnopqrstuvwx'
|
||||||
|
|
||||||
|
|
||||||
def gridsquare(lat, lng):
|
def gridsquare(lat, lng):
|
||||||
|
"""Calculates a maidenhead grid square from a lat/long
|
||||||
|
|
||||||
|
Used when we get a SiDS submission, we want to store and display the
|
||||||
|
location of the submitter as a grid square.
|
||||||
|
|
||||||
|
:returns: a string of the grid square, ie: EM69uf
|
||||||
|
"""
|
||||||
if not -180 <= lng < 180:
|
if not -180 <= lng < 180:
|
||||||
return False
|
return False
|
||||||
if not -90 <= lat < 90:
|
if not -90 <= lat < 90:
|
||||||
|
@ -38,6 +46,11 @@ def gridsquare(lat, lng):
|
||||||
|
|
||||||
|
|
||||||
def get_apikey(user):
|
def get_apikey(user):
|
||||||
|
"""If necessary, create, then return an API key for a user
|
||||||
|
|
||||||
|
:param user: a SatNOGS DB User object
|
||||||
|
:returns: user API token
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
token = Token.objects.get(user=user)
|
token = Token.objects.get(user=user)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -45,7 +58,9 @@ def get_apikey(user):
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: remove
|
||||||
def cache_get_key(*args, **kwargs):
|
def cache_get_key(*args, **kwargs):
|
||||||
|
"""Unused, needs removing"""
|
||||||
import hashlib
|
import hashlib
|
||||||
serialise = []
|
serialise = []
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
@ -57,9 +72,13 @@ def cache_get_key(*args, **kwargs):
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: remove
|
||||||
def cache_for(time):
|
def cache_for(time):
|
||||||
|
"""Unused, needs removing"""
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
|
"""Unused, needs removing"""
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
"""Unused, needs removing"""
|
||||||
key = cache_get_key(func.__name__, *args, **kwargs)
|
key = cache_get_key(func.__name__, *args, **kwargs)
|
||||||
result = cache.get(key)
|
result = cache.get(key)
|
||||||
if not result:
|
if not result:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django management command to delete satellites"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ from db.base.models import Satellite
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
"""django management command to delete satellites"""
|
||||||
help = 'Delete selected Satellites'
|
help = 'Delete selected Satellites'
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django management command to fetch data (TLEs, etc)"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ from db.base.models import DemodData, Satellite, TransmitterEntry
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
"""django management command to fetch data (TLEs, etc)"""
|
||||||
help = 'Fetch Satellite data from Network'
|
help = 'Fetch Satellite data from Network'
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django management command to fetch satellites"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ from db.base.tasks import update_satellite
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
"""django management command to fetch satellites"""
|
||||||
help = 'Updates/Inserts Name for certain Satellites'
|
help = 'Updates/Inserts Name for certain Satellites'
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django management command to initialize a new database"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -6,6 +7,7 @@ from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
"""django management command to initialize a new database"""
|
||||||
help = 'Create initial fixtures'
|
help = 'Create initial fixtures'
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB django management command to update TLE entries"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ from db.base.tasks import update_all_tle
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
"""django management command to update TLE entries"""
|
||||||
help = 'Update TLEs for existing Satellites'
|
help = 'Update TLEs for existing Satellites'
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Django database model for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -33,6 +34,11 @@ SERVICE_TYPE = [
|
||||||
|
|
||||||
|
|
||||||
def _name_payload_frame(instance, filename):
|
def _name_payload_frame(instance, filename):
|
||||||
|
"""Returns a unique, timestamped path and filename for a payload
|
||||||
|
|
||||||
|
:param filename: the original filename submitted
|
||||||
|
:returns: path string with timestamped subfolders and filename
|
||||||
|
"""
|
||||||
today = now()
|
today = now()
|
||||||
folder = 'payload_frames/{0}/{1}/{2}/'.format(today.year, today.month, today.day)
|
folder = 'payload_frames/{0}/{1}/{2}/'.format(today.year, today.month, today.day)
|
||||||
ext = 'raw'
|
ext = 'raw'
|
||||||
|
@ -53,11 +59,13 @@ def _gen_observer(sender, instance, created, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def _set_is_decoded(sender, instance, **kwargs):
|
def _set_is_decoded(sender, instance, **kwargs):
|
||||||
|
"""Returns true if payload_decoded has data"""
|
||||||
instance.is_decoded = instance.payload_decoded != ''
|
instance.is_decoded = instance.payload_decoded != ''
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Mode(models.Model):
|
class Mode(models.Model):
|
||||||
|
"""A satellite transmitter RF mode. For example: FM"""
|
||||||
name = models.CharField(max_length=10, unique=True)
|
name = models.CharField(max_length=10, unique=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -84,9 +92,17 @@ class Satellite(models.Model):
|
||||||
ordering = ['norad_cat_id']
|
ordering = ['norad_cat_id']
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
|
"""Returns the markdown-processed satellite description
|
||||||
|
|
||||||
|
:returns: the markdown-processed satellite description
|
||||||
|
"""
|
||||||
return markdown(self.description)
|
return markdown(self.description)
|
||||||
|
|
||||||
def get_image(self):
|
def get_image(self):
|
||||||
|
"""Returns an image for the satellite
|
||||||
|
|
||||||
|
:returns: the saved image for the satellite, or a default
|
||||||
|
"""
|
||||||
if self.image and hasattr(self.image, 'url'):
|
if self.image and hasattr(self.image, 'url'):
|
||||||
return self.image.url
|
return self.image.url
|
||||||
else:
|
else:
|
||||||
|
@ -94,20 +110,39 @@ class Satellite(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def transmitters(self):
|
def transmitters(self):
|
||||||
|
"""Returns valid transmitters for this Satellite
|
||||||
|
|
||||||
|
:returns: the valid transmitters for this Satellite
|
||||||
|
"""
|
||||||
return Transmitter.objects.filter(satellite=self.id).exclude(status='invalid')
|
return Transmitter.objects.filter(satellite=self.id).exclude(status='invalid')
|
||||||
|
|
||||||
|
# TODO: rename this to sound more like a count
|
||||||
@property
|
@property
|
||||||
def pending_transmitter_suggestions(self):
|
def pending_transmitter_suggestions(self):
|
||||||
|
"""Returns number of pending transmitter suggestions for this Satellite
|
||||||
|
|
||||||
|
:returns: number of pending transmitter suggestions for this Satellite
|
||||||
|
"""
|
||||||
pending = TransmitterSuggestion.objects.filter(satellite=self.id).count()
|
pending = TransmitterSuggestion.objects.filter(satellite=self.id).count()
|
||||||
return pending
|
return pending
|
||||||
|
|
||||||
|
# TODO: rename this to sound more like a count
|
||||||
@property
|
@property
|
||||||
def has_telemetry_data(self):
|
def has_telemetry_data(self):
|
||||||
|
"""Returns number of DemodData for this Satellite
|
||||||
|
|
||||||
|
:returns: number of DemodData for this Satellite
|
||||||
|
"""
|
||||||
has_data = DemodData.objects.filter(satellite=self.id).count()
|
has_data = DemodData.objects.filter(satellite=self.id).count()
|
||||||
return has_data
|
return has_data
|
||||||
|
|
||||||
|
# TODO: rename this to sound more like a count
|
||||||
@property
|
@property
|
||||||
def has_telemetry_decoders(self):
|
def has_telemetry_decoders(self):
|
||||||
|
"""Returns number of Telemetry objects for this Satellite
|
||||||
|
|
||||||
|
:returns: number of Telemetry objects for this Satellite
|
||||||
|
"""
|
||||||
has_decoders = Telemetry.objects.filter(satellite=self.id).exclude(decoder='').count()
|
has_decoders = Telemetry.objects.filter(satellite=self.id).exclude(decoder='').count()
|
||||||
return has_decoders
|
return has_decoders
|
||||||
|
|
||||||
|
@ -164,11 +199,18 @@ class TransmitterEntry(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class TransmitterSuggestionManager(models.Manager):
|
class TransmitterSuggestionManager(models.Manager):
|
||||||
|
"""Django Manager for TransmitterSuggestions
|
||||||
|
|
||||||
|
TransmitterSuggestions are TransmitterEntry objects that have been
|
||||||
|
submitted (suggested) but not yet reviewed
|
||||||
|
"""
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
"""Returns TransmitterEntries that have not been reviewed"""
|
||||||
return TransmitterEntry.objects.filter(reviewed=False)
|
return TransmitterEntry.objects.filter(reviewed=False)
|
||||||
|
|
||||||
|
|
||||||
class TransmitterSuggestion(TransmitterEntry):
|
class TransmitterSuggestion(TransmitterEntry):
|
||||||
|
"""TransmitterSuggestion is an unreviewed TransmitterEntry object"""
|
||||||
objects = TransmitterSuggestionManager()
|
objects = TransmitterSuggestionManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -177,7 +219,14 @@ class TransmitterSuggestion(TransmitterEntry):
|
||||||
|
|
||||||
|
|
||||||
class TransmitterManager(models.Manager):
|
class TransmitterManager(models.Manager):
|
||||||
|
"""Django Manager for Transmitter objects"""
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
"""Returns query of TransmitterEntries
|
||||||
|
|
||||||
|
:returns: the latest revision of a TransmitterEntry for each
|
||||||
|
TransmitterEntry uuid associated with this Satellite that is
|
||||||
|
both reviewed and approved
|
||||||
|
"""
|
||||||
subquery = TransmitterEntry.objects.filter(
|
subquery = TransmitterEntry.objects.filter(
|
||||||
reviewed=True, approved=True
|
reviewed=True, approved=True
|
||||||
).filter(uuid=OuterRef('uuid')).order_by('-created')
|
).filter(uuid=OuterRef('uuid')).order_by('-created')
|
||||||
|
@ -187,6 +236,9 @@ class TransmitterManager(models.Manager):
|
||||||
|
|
||||||
|
|
||||||
class Transmitter(TransmitterEntry):
|
class Transmitter(TransmitterEntry):
|
||||||
|
"""Associates a generic Transmitter object with their TransmitterEntries
|
||||||
|
that are managed by TransmitterManager
|
||||||
|
"""
|
||||||
objects = TransmitterManager()
|
objects = TransmitterManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -195,7 +247,7 @@ class Transmitter(TransmitterEntry):
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Telemetry(models.Model):
|
class Telemetry(models.Model):
|
||||||
"""Model for satellite telemtry decoders."""
|
"""Model for satellite telemetry decoders."""
|
||||||
satellite = models.ForeignKey(
|
satellite = models.ForeignKey(
|
||||||
Satellite, null=True, related_name='telemetries', on_delete=models.SET_NULL
|
Satellite, null=True, related_name='telemetries', on_delete=models.SET_NULL
|
||||||
)
|
)
|
||||||
|
@ -244,13 +296,24 @@ class DemodData(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'data-for-{0}'.format(self.satellite.norad_cat_id)
|
return 'data-for-{0}'.format(self.satellite.norad_cat_id)
|
||||||
|
|
||||||
|
# TODO: this is a relic of the first attempt at payload decoding and
|
||||||
|
# should be refactored out or changed to actually fetch the decoded
|
||||||
|
# frame (from influx?)
|
||||||
def display_decoded(self):
|
def display_decoded(self):
|
||||||
|
"""Returns the contents of payload_decoded
|
||||||
|
|
||||||
|
:returns: json-formatted contents of payload_decoded
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
json.dumps(self.payload_decoded)
|
json.dumps(self.payload_decoded)
|
||||||
except Exception:
|
except Exception:
|
||||||
'{}'
|
'{}'
|
||||||
|
|
||||||
def display_frame(self):
|
def display_frame(self):
|
||||||
|
"""Returns the contents of the saved frame file for this DemodData
|
||||||
|
|
||||||
|
:returns: the contents of the saved frame file for this DemodData
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with open(self.payload_frame.path) as frame_file:
|
with open(self.payload_frame.path) as frame_file:
|
||||||
return frame_file.read()
|
return frame_file.read()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB Celery task functions"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Django template tags for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ register = template.Library()
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def active(request, urls):
|
def active(request, urls):
|
||||||
|
"""Returns if this is an active URL"""
|
||||||
if request.path in (reverse(url) for url in urls.split()):
|
if request.path in (reverse(url) for url in urls.split()):
|
||||||
return 'active'
|
return 'active'
|
||||||
return None
|
return None
|
||||||
|
@ -17,6 +19,7 @@ def active(request, urls):
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def frq(value):
|
def frq(value):
|
||||||
|
"""Returns Hz formatted frequency html string"""
|
||||||
try:
|
try:
|
||||||
to_format = float(value)
|
to_format = float(value)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB test suites"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ DATA_SOURCE_IDS = [c[0] for c in DATA_SOURCES]
|
||||||
|
|
||||||
|
|
||||||
def generate_payload():
|
def generate_payload():
|
||||||
|
"""Create data payloads"""
|
||||||
payload = '{0:b}'.format(random.randint(500000000, 510000000))
|
payload = '{0:b}'.format(random.randint(500000000, 510000000))
|
||||||
digits = 1824
|
digits = 1824
|
||||||
while digits:
|
while digits:
|
||||||
|
@ -28,6 +30,7 @@ def generate_payload():
|
||||||
|
|
||||||
|
|
||||||
def generate_payload_name():
|
def generate_payload_name():
|
||||||
|
"""Create payload names"""
|
||||||
filename = datetime.strftime(
|
filename = datetime.strftime(
|
||||||
fuzzy.FuzzyDateTime(now() - timedelta(days=10), now()).fuzz(), '%Y%m%dT%H%M%SZ'
|
fuzzy.FuzzyDateTime(now() - timedelta(days=10), now()).fuzz(), '%Y%m%dT%H%M%SZ'
|
||||||
)
|
)
|
||||||
|
@ -35,6 +38,7 @@ def generate_payload_name():
|
||||||
|
|
||||||
|
|
||||||
def get_valid_satellites():
|
def get_valid_satellites():
|
||||||
|
"""Returns valid satellites"""
|
||||||
qs = Transmitter.objects.all()
|
qs = Transmitter.objects.all()
|
||||||
satellites = Satellite.objects.filter(transmitters__in=qs).distinct()
|
satellites = Satellite.objects.filter(transmitters__in=qs).distinct()
|
||||||
return satellites
|
return satellites
|
||||||
|
@ -89,6 +93,7 @@ class TransmitterFactory(factory.django.DjangoModelFactory):
|
||||||
|
|
||||||
|
|
||||||
class TransmitterSuggestionFactory(factory.django.DjangoModelFactory):
|
class TransmitterSuggestionFactory(factory.django.DjangoModelFactory):
|
||||||
|
"""TransmitterSuggestion model factory."""
|
||||||
description = fuzzy.FuzzyText()
|
description = fuzzy.FuzzyText()
|
||||||
status = fuzzy.FuzzyChoice(choices=['active', 'inactive', 'invalid'])
|
status = fuzzy.FuzzyChoice(choices=['active', 'inactive', 'invalid'])
|
||||||
type = fuzzy.FuzzyChoice(choices=['Transmitter', 'Transceiver', 'Transponder'])
|
type = fuzzy.FuzzyChoice(choices=['Transmitter', 'Transceiver', 'Transponder'])
|
||||||
|
@ -111,6 +116,7 @@ class TransmitterSuggestionFactory(factory.django.DjangoModelFactory):
|
||||||
|
|
||||||
|
|
||||||
class TelemetryFactory(factory.django.DjangoModelFactory):
|
class TelemetryFactory(factory.django.DjangoModelFactory):
|
||||||
|
"""Telemetry model factory."""
|
||||||
satellite = factory.SubFactory(SatelliteFactory)
|
satellite = factory.SubFactory(SatelliteFactory)
|
||||||
name = fuzzy.FuzzyText()
|
name = fuzzy.FuzzyText()
|
||||||
schema = '{}'
|
schema = '{}'
|
||||||
|
@ -121,6 +127,7 @@ class TelemetryFactory(factory.django.DjangoModelFactory):
|
||||||
|
|
||||||
|
|
||||||
class DemodDataFactory(factory.django.DjangoModelFactory):
|
class DemodDataFactory(factory.django.DjangoModelFactory):
|
||||||
|
"""DemodData model factory."""
|
||||||
satellite = factory.SubFactory(SatelliteFactory)
|
satellite = factory.SubFactory(SatelliteFactory)
|
||||||
transmitter = factory.SubFactory(TransmitterFactory)
|
transmitter = factory.SubFactory(TransmitterFactory)
|
||||||
app_source = fuzzy.FuzzyChoice(choices=DATA_SOURCE_IDS)
|
app_source = fuzzy.FuzzyChoice(choices=DATA_SOURCE_IDS)
|
||||||
|
@ -144,6 +151,7 @@ class HomeViewTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_home_page(self):
|
def test_home_page(self):
|
||||||
|
"""Tests for a known string in the SatNOGS DB home page template"""
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, 'SatNOGS DB is, and will always be, an open database.')
|
self.assertContains(response, 'SatNOGS DB is, and will always be, an open database.')
|
||||||
|
|
||||||
|
@ -160,6 +168,7 @@ class SatelliteViewTest(TestCase):
|
||||||
self.satellite.save()
|
self.satellite.save()
|
||||||
|
|
||||||
def test_satellite_page(self):
|
def test_satellite_page(self):
|
||||||
|
"""Tests for satellite name in a SatNOGS DB satellite page"""
|
||||||
response = self.client.get('/satellite/%s/' % self.satellite.norad_cat_id)
|
response = self.client.get('/satellite/%s/' % self.satellite.norad_cat_id)
|
||||||
self.assertContains(response, self.satellite.name)
|
self.assertContains(response, self.satellite.name)
|
||||||
|
|
||||||
|
@ -171,6 +180,7 @@ class AboutViewTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_about_page(self):
|
def test_about_page(self):
|
||||||
|
"""Tests for a known string in the SatNOGS DB about page template"""
|
||||||
response = self.client.get('/about/')
|
response = self.client.get('/about/')
|
||||||
self.assertContains(response, 'SatNOGS DB is an effort to create an hollistic')
|
self.assertContains(response, 'SatNOGS DB is an effort to create an hollistic')
|
||||||
|
|
||||||
|
@ -182,5 +192,6 @@ class FaqViewTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_faq_page(self):
|
def test_faq_page(self):
|
||||||
|
"""Tests for a known string in the SatNOGS DB FAQ page template"""
|
||||||
response = self.client.get('/faq/')
|
response = self.client.get('/faq/')
|
||||||
self.assertContains(response, 'How do I suggest a new transmitter?')
|
self.assertContains(response, 'How do I suggest a new transmitter?')
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Django base URL routings for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Miscellaneous functions for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -19,7 +20,10 @@ LOGGER = logging.getLogger('db')
|
||||||
|
|
||||||
|
|
||||||
def calculate_statistics():
|
def calculate_statistics():
|
||||||
"""View to create statistics endpoint."""
|
"""Calculates statistics about the data we have in DB
|
||||||
|
|
||||||
|
:returns: a dictionary of statistics
|
||||||
|
"""
|
||||||
satellites = Satellite.objects.all()
|
satellites = Satellite.objects.all()
|
||||||
transmitters = Transmitter.objects.all()
|
transmitters = Transmitter.objects.all()
|
||||||
modes = Mode.objects.all()
|
modes = Mode.objects.all()
|
||||||
|
@ -140,7 +144,10 @@ def calculate_statistics():
|
||||||
|
|
||||||
|
|
||||||
def create_point(fields, satellite, telemetry, demoddata, version):
|
def create_point(fields, satellite, telemetry, demoddata, version):
|
||||||
"""Create a decoded data point"""
|
"""Create a decoded data point in JSON format that is influxdb compatible
|
||||||
|
|
||||||
|
:returns: a JSON formatted time series data point
|
||||||
|
"""
|
||||||
point = [
|
point = [
|
||||||
{
|
{
|
||||||
'time': demoddata.timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
'time': demoddata.timestamp.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
||||||
|
@ -174,7 +181,12 @@ def write_influx(json_obj):
|
||||||
|
|
||||||
|
|
||||||
def decode_data(norad, period=None):
|
def decode_data(norad, period=None):
|
||||||
"""Decode data for a satellite, with an option to limit the scope."""
|
"""Decode data for a satellite, with an option to limit the scope.
|
||||||
|
|
||||||
|
:param norad: the NORAD ID of the satellite to decode data for
|
||||||
|
:param period: if period exists, only attempt to decode the last 4 hours,
|
||||||
|
otherwise attempt to decode everything
|
||||||
|
"""
|
||||||
sat = Satellite.objects.get(norad_cat_id=norad)
|
sat = Satellite.objects.get(norad_cat_id=norad)
|
||||||
if sat.has_telemetry_decoders:
|
if sat.has_telemetry_decoders:
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
|
@ -241,6 +253,10 @@ def decode_data(norad, period=None):
|
||||||
|
|
||||||
# Caches stats about satellites and data
|
# Caches stats about satellites and data
|
||||||
def cache_statistics():
|
def cache_statistics():
|
||||||
|
"""Populate a django cache with statistics from data in DB
|
||||||
|
|
||||||
|
.. seealso:: calculate_statistics
|
||||||
|
"""
|
||||||
statistics = calculate_statistics()
|
statistics = calculate_statistics()
|
||||||
cache.set('stats_transmitters', statistics, 60 * 60 * 2)
|
cache.set('stats_transmitters', statistics, 60 * 60 * 2)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Base django views for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -29,7 +30,10 @@ LOGGER = logging.getLogger('db')
|
||||||
|
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
"""View to render home page."""
|
"""View to render home page.
|
||||||
|
|
||||||
|
:returns: base/home.html
|
||||||
|
"""
|
||||||
satellites = Satellite.objects.all()
|
satellites = Satellite.objects.all()
|
||||||
transmitter_suggestions = TransmitterSuggestion.objects.count()
|
transmitter_suggestions = TransmitterSuggestion.objects.count()
|
||||||
contributors = User.objects.filter(is_active=1).count()
|
contributors = User.objects.filter(is_active=1).count()
|
||||||
|
@ -51,23 +55,36 @@ def home(request):
|
||||||
|
|
||||||
|
|
||||||
def custom_404(request):
|
def custom_404(request):
|
||||||
"""Custom 404 error handler."""
|
"""Custom 404 error handler.
|
||||||
|
|
||||||
|
:returns: 404.html
|
||||||
|
"""
|
||||||
return HttpResponseNotFound(render(request, '404.html'))
|
return HttpResponseNotFound(render(request, '404.html'))
|
||||||
|
|
||||||
|
|
||||||
def custom_500(request):
|
def custom_500(request):
|
||||||
"""Custom 500 error handler."""
|
"""Custom 500 error handler.
|
||||||
|
|
||||||
|
:returns: 500.html
|
||||||
|
"""
|
||||||
return HttpResponseServerError(render(request, '500.html'))
|
return HttpResponseServerError(render(request, '500.html'))
|
||||||
|
|
||||||
|
|
||||||
def robots(request):
|
def robots(request):
|
||||||
|
"""robots.txt handler
|
||||||
|
|
||||||
|
:returns: robots.txt
|
||||||
|
"""
|
||||||
data = render(request, 'robots.txt', {'environment': settings.ENVIRONMENT})
|
data = render(request, 'robots.txt', {'environment': settings.ENVIRONMENT})
|
||||||
response = HttpResponse(data, content_type='text/plain; charset=utf-8')
|
response = HttpResponse(data, content_type='text/plain; charset=utf-8')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def satellite(request, norad):
|
def satellite(request, norad):
|
||||||
"""View to render satellite page."""
|
"""View to render satellite page.
|
||||||
|
|
||||||
|
:returns: base/satellite.html
|
||||||
|
"""
|
||||||
satellite = get_object_or_404(Satellite.objects, norad_cat_id=norad)
|
satellite = get_object_or_404(Satellite.objects, norad_cat_id=norad)
|
||||||
transmitter_suggestions = TransmitterSuggestion.objects.filter(satellite=satellite)
|
transmitter_suggestions = TransmitterSuggestion.objects.filter(satellite=satellite)
|
||||||
for transmitter_suggestion in transmitter_suggestions:
|
for transmitter_suggestion in transmitter_suggestions:
|
||||||
|
@ -108,7 +125,13 @@ def satellite(request, norad):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def request_export(request, norad, period=None):
|
def request_export(request, norad, period=None):
|
||||||
"""View to request frames export download."""
|
"""View to request frames export download.
|
||||||
|
|
||||||
|
This triggers a request to collect and zip up the requested data for
|
||||||
|
download, which the user is notified of via email when the celery task is
|
||||||
|
completed.
|
||||||
|
:returns: the originating satellite page
|
||||||
|
"""
|
||||||
export_frames.delay(norad, request.user.email, request.user.pk, period)
|
export_frames.delay(norad, request.user.email, request.user.pk, period)
|
||||||
messages.success(
|
messages.success(
|
||||||
request, ('Your download request was received. '
|
request, ('Your download request was received. '
|
||||||
|
@ -120,7 +143,10 @@ def request_export(request, norad, period=None):
|
||||||
@login_required
|
@login_required
|
||||||
@require_POST
|
@require_POST
|
||||||
def transmitter_suggestion(request):
|
def transmitter_suggestion(request):
|
||||||
"""View to process transmitter suggestion form"""
|
"""View to process transmitter suggestion form
|
||||||
|
|
||||||
|
:returns: the originating satellite page unless an error occurs
|
||||||
|
"""
|
||||||
transmitter_form = TransmitterEntryForm(request.POST)
|
transmitter_form = TransmitterEntryForm(request.POST)
|
||||||
if transmitter_form.is_valid():
|
if transmitter_form.is_valid():
|
||||||
transmitter = transmitter_form.save(commit=False)
|
transmitter = transmitter_form.save(commit=False)
|
||||||
|
@ -175,17 +201,28 @@ def transmitter_suggestion(request):
|
||||||
|
|
||||||
|
|
||||||
def about(request):
|
def about(request):
|
||||||
"""View to render about page."""
|
"""View to render about page.
|
||||||
|
|
||||||
|
:returns: base/about.html
|
||||||
|
"""
|
||||||
return render(request, 'base/about.html')
|
return render(request, 'base/about.html')
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: replace this with a link to docs in the wiki which won't require code
|
||||||
|
# updates to maintain
|
||||||
def faq(request):
|
def faq(request):
|
||||||
"""View to render faq page."""
|
"""View to render faq page.
|
||||||
|
|
||||||
|
:returns: base/faq.html
|
||||||
|
"""
|
||||||
return render(request, 'base/faq.html')
|
return render(request, 'base/faq.html')
|
||||||
|
|
||||||
|
|
||||||
def stats(request):
|
def stats(request):
|
||||||
"""View to render stats page."""
|
"""View to render stats page.
|
||||||
|
|
||||||
|
:returns: base/stats.html
|
||||||
|
"""
|
||||||
satellites = cache.get('stats_satellites')
|
satellites = cache.get('stats_satellites')
|
||||||
observers = cache.get('stats_observers')
|
observers = cache.get('stats_observers')
|
||||||
# TODO this will never succeed, cache_statistics() runs too long to be live
|
# TODO this will never succeed, cache_statistics() runs too long to be live
|
||||||
|
@ -198,6 +235,10 @@ def stats(request):
|
||||||
|
|
||||||
|
|
||||||
def statistics(request):
|
def statistics(request):
|
||||||
|
"""Triggers a refresh of cached statistics if the cache does not exist
|
||||||
|
|
||||||
|
:returns: JsonResponse of statistics
|
||||||
|
"""
|
||||||
statistics = cache.get('stats_transmitters')
|
statistics = cache.get('stats_transmitters')
|
||||||
if not statistics:
|
if not statistics:
|
||||||
cache_statistics()
|
cache_statistics()
|
||||||
|
@ -205,8 +246,12 @@ def statistics(request):
|
||||||
return JsonResponse(statistics, safe=False)
|
return JsonResponse(statistics, safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: this is confusing as we call it "edit" but it is the users "settings"
|
||||||
@login_required
|
@login_required
|
||||||
def users_edit(request):
|
def users_edit(request):
|
||||||
"""View to render user settings page."""
|
"""View to render user settings page.
|
||||||
|
|
||||||
|
:returns: base/users_edit.html
|
||||||
|
"""
|
||||||
token = get_apikey(request.user)
|
token = get_apikey(request.user)
|
||||||
return render(request, 'base/users_edit.html', {'token': token})
|
return render(request, 'base/users_edit.html', {'token': token})
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""SatNOGS DB celery task workers"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ APP.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
||||||
|
|
||||||
@APP.on_after_finalize.connect
|
@APP.on_after_finalize.connect
|
||||||
def setup_periodic_tasks(sender, **kwargs):
|
def setup_periodic_tasks(sender, **kwargs):
|
||||||
|
"""Initializes celery tasks that need to run on a scheduled basis"""
|
||||||
from db.base.tasks import update_all_tle, background_cache_statistics, decode_recent_data
|
from db.base.tasks import update_all_tle, background_cache_statistics, decode_recent_data
|
||||||
|
|
||||||
sender.add_periodic_task(RUN_DAILY, update_all_tle.s(), name='update-all-tle')
|
sender.add_periodic_task(RUN_DAILY, update_all_tle.s(), name='update-all-tle')
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
"""SatNOGS DB Application django settings
|
||||||
|
|
||||||
|
For local installation settings please copy .env-dist to .env and edit
|
||||||
|
the appropriate settings in that file. You should not need to edit this
|
||||||
|
file for local settings!
|
||||||
|
"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
""" Base Django URL mapping for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
"""WSGI module for SatNOGS DB"""
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
unicode_literals
|
unicode_literals
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue