1
0
Fork 0

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
Corey Shields 2019-07-12 22:36:18 -04:00
parent dcccb1770e
commit 2ec2fd2a4d
34 changed files with 299 additions and 18 deletions

View File

@ -4,7 +4,6 @@ load-plugins=pylint_django
[MESSAGES CONTROL]
disable=
C0111,
C0411,
C0412,
E1101,

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
"""SatNOGS DB Auth0 login module admin class"""
from __future__ import unicode_literals
# from django.contrib import admin

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
"""SatNOGS DB Auth0 login app config"""
from __future__ import unicode_literals
from django.apps import AppConfig
class Auth0LoginConfig(AppConfig):
"""Set the name of the django app for auth0login"""
name = 'auth0login'

View File

@ -1,3 +1,4 @@
"""SatNOGS DB Auth0 login module auth backend"""
import requests
from social_core.backends.oauth import BaseOAuth2

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
"""SatNOGS DB Auth0 login module models"""
from __future__ import unicode_literals
# from django.db import models

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
"""SatNOGS DB Auth0 login module test suites"""
from __future__ import unicode_literals
# from django.test import TestCase

View File

@ -1,3 +1,4 @@
"""SatNOGS DB Auth0 login module URL routers"""
from django.conf.urls import include, url
from . import views

View File

@ -1,7 +1,9 @@
"""SatNOGS DB Auth0 login module views"""
from __future__ import unicode_literals
from django.shortcuts import render
def index(request):
"""Returns the index view"""
return render(request, 'index.html')

View File

@ -1,3 +1,4 @@
"""The core django app for SatNOGS DB"""
from __future__ import absolute_import
from ._version import get_versions

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django rest framework Filters class"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -9,9 +10,11 @@ from db.base.models import DemodData, Satellite, Transmitter
class TransmitterViewFilter(FilterSet):
"""SatNOGS DB Transmitter API View Filter"""
alive = filters.BooleanFilter(field_name='status', label='Alive', method='filter_status')
def filter_status(self, queryset, name, value):
"""Returns Transmitters that are either functional or non-functional"""
if value:
return queryset.filter(status='functional')
else:
@ -23,7 +26,10 @@ class TransmitterViewFilter(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')
class Meta:
@ -32,6 +38,7 @@ class SatelliteViewFilter(FilterSet):
class TelemetryViewFilter(FilterSet):
"""SatNOGS DB Telemetry API View Filter"""
satellite = django_filters.NumberFilter(
field_name='satellite__norad_cat_id', lookup_expr='exact'
)

View File

@ -1,3 +1,4 @@
"""SatNOGS DB API serializers, django rest framework"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -8,18 +9,21 @@ from db.base.models import TRANSMITTER_STATUS, DemodData, Mode, Satellite, \
class ModeSerializer(serializers.ModelSerializer):
"""SatNOGS DB Mode API Serializer"""
class Meta:
model = Mode
fields = ('id', 'name')
class SatelliteSerializer(serializers.ModelSerializer):
"""SatNOGS DB Satellite API Serializer"""
class Meta:
model = Satellite
fields = ('norad_cat_id', 'name', 'names', 'image', 'status', 'decayed')
class TransmitterSerializer(serializers.ModelSerializer):
"""SatNOGS DB Transmitter API Serializer"""
norad_cat_id = serializers.SerializerMethodField()
mode_id = serializers.SerializerMethodField()
mode = serializers.SerializerMethodField()
@ -36,25 +40,30 @@ class TransmitterSerializer(serializers.ModelSerializer):
# Keeping alive field for compatibility issues
def get_alive(self, obj):
"""Returns transmitter status"""
return obj.status == TRANSMITTER_STATUS[0]
def get_mode_id(self, obj):
"""Returns mode ID"""
try:
return obj.mode.id
except Exception:
return None
def get_mode(self, obj):
"""Returns mode name"""
try:
return obj.mode.name
except Exception:
return None
def get_norad_cat_id(self, obj):
"""Returns Satellite NORAD ID"""
return obj.satellite.norad_cat_id
class TelemetrySerializer(serializers.ModelSerializer):
"""SatNOGS DB Telemetry API Serializer"""
norad_cat_id = serializers.SerializerMethodField()
transmitter = serializers.SerializerMethodField()
schema = serializers.SerializerMethodField()
@ -69,28 +78,36 @@ class TelemetrySerializer(serializers.ModelSerializer):
)
def get_norad_cat_id(self, obj):
"""Returns Satellite NORAD ID for this Transmitter"""
return obj.satellite.norad_cat_id
def get_transmitter(self, obj):
"""Returns Transmitter UUID"""
try:
return obj.transmitter.uuid
except Exception:
return ''
# TODO: this is a relic of the old data decoding method, needs revisiting
def get_schema(self, obj):
"""Returns Transmitter telemetry schema"""
try:
return obj.payload_telemetry.schema
except Exception:
return ''
# TODO: this is a relic of the old data decoding method, needs revisiting
def get_decoded(self, obj):
"""Returns the payload_decoded field"""
return obj.payload_decoded
def get_frame(self, obj):
"""Returns the payload frame"""
return obj.display_frame()
class SidsSerializer(serializers.ModelSerializer):
"""SatNOGS DB SiDS API Serializer"""
class Meta:
model = DemodData
fields = ('satellite', 'payload_frame', 'station', 'lat', 'lng', 'timestamp', 'app_source')

View File

@ -1,3 +1,4 @@
"""SatNOGS DB API test suites"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -21,10 +22,12 @@ class ModeViewApiTest(TestCase):
self.mode.save()
def test_list(self):
"""Test the API modes list"""
response = self.client.get('/api/modes/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve(self):
"""Test the API mode retrieval"""
response = self.client.get('/api/modes/{0}/'.format(self.mode.id), format='json')
self.assertContains(response, self.mode.name)
@ -41,10 +44,12 @@ class SatelliteViewApiTest(TestCase):
self.satellite.save()
def test_list(self):
"""Test the Satellite API listing"""
response = self.client.get('/api/satellites/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve(self):
"""Test the Satellite API retrieval"""
response = self.client.get(
'/api/satellites/{0}/'.format(self.satellite.norad_cat_id), format='json'
)
@ -64,10 +69,12 @@ class TransmitterViewApiTest(TestCase):
self.transmitter.save()
def test_list(self):
"""Test the Transmitter API listing"""
response = self.client.get('/api/transmitters/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve(self):
"""Test the Transmitter API retrieval"""
response = self.client.get(
'/api/transmitters/{0}/'.format(self.transmitter.uuid), format='json'
)
@ -86,9 +93,11 @@ class TelemetryViewApiTest(TestCase):
self.datum.save()
def test_list(self):
"""Test the Telemetry API listing"""
response = self.client.get('/api/telemetry/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve(self):
"""Test the Telemetry API retrieval"""
response = self.client.get('/api/telemetry/{0}/'.format(self.datum.id), format='json')
self.assertContains(response, self.datum.observer)

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django rest framework API url routings"""
from __future__ import absolute_import, division, print_function, \
unicode_literals

View File

@ -1,3 +1,4 @@
"""SatNOGS DB API django rest framework Views"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -13,11 +14,13 @@ from db.base.tasks import update_satellite
class ModeView(viewsets.ReadOnlyModelViewSet):
"""SatNOGS DB Mode API view class"""
queryset = Mode.objects.all()
serializer_class = serializers.ModeSerializer
class SatelliteView(viewsets.ReadOnlyModelViewSet):
"""SatNOGS DB Satellite API view class"""
queryset = Satellite.objects.all()
serializer_class = serializers.SatelliteSerializer
filter_class = filters.SatelliteViewFilter
@ -25,6 +28,7 @@ class SatelliteView(viewsets.ReadOnlyModelViewSet):
class TransmitterView(viewsets.ReadOnlyModelViewSet):
"""SatNOGS DB Transmitter API view class"""
queryset = Transmitter.objects.all()
serializer_class = serializers.TransmitterSerializer
filter_class = filters.TransmitterViewFilter
@ -33,6 +37,7 @@ class TransmitterView(viewsets.ReadOnlyModelViewSet):
class TelemetryView(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin,
viewsets.GenericViewSet):
"""SatNOGS DB Telemetry API view class"""
queryset = DemodData.objects.all()
serializer_class = serializers.TelemetrySerializer
filter_class = filters.TelemetryViewFilter

View File

@ -1,3 +1,4 @@
"""Defines functions and settings for the django admin interface"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -17,16 +18,25 @@ from db.base.tasks import check_celery, decode_all_data
@admin.register(Mode)
class ModeAdmin(admin.ModelAdmin):
"""Defines Mode view in django admin UI"""
list_display = ('name', )
@admin.register(Satellite)
class SatelliteAdmin(admin.ModelAdmin):
"""Defines Satellite view in django admin UI"""
list_display = ('name', 'norad_cat_id', 'status', 'decayed')
search_fields = ('name', 'norad_cat_id')
list_filter = ('status', 'decayed')
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()
my_urls = [
url(r'^check_celery/$', self.check_celery, name='check_celery'),
@ -39,6 +49,14 @@ class SatelliteAdmin(admin.ModelAdmin):
return my_urls + urls
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:
investigator = check_celery.delay()
except socket_error as error:
@ -54,9 +72,15 @@ class SatelliteAdmin(admin.ModelAdmin):
finally:
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):
"""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)
messages.success(request, 'Decode task was triggered successfully!')
return redirect(reverse('admin:index'))
@ -64,6 +88,7 @@ class SatelliteAdmin(admin.ModelAdmin):
@admin.register(TransmitterEntry)
class TransmitterEntryAdmin(admin.ModelAdmin):
"""Defines TransmitterEntry view in django admin UI"""
list_display = (
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'reviewed',
@ -84,6 +109,7 @@ class TransmitterEntryAdmin(admin.ModelAdmin):
@admin.register(TransmitterSuggestion)
class TransmitterSuggestionAdmin(admin.ModelAdmin):
"""Defines TransmitterSuggestion view in django admin UI"""
list_display = (
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
@ -104,6 +130,12 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
actions = ['approve_suggestion', 'reject_suggestion']
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)
if not request.user.has_perm('base.delete_transmittersuggestion'):
if 'delete_selected' in actions:
@ -111,6 +143,11 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
return actions
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)
for entry in queryset:
entry.approved = True
@ -129,6 +166,11 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
approve_suggestion.short_description = 'Approve selected transmitter suggestions'
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)
for entry in queryset:
entry.created = datetime.utcnow()
@ -149,6 +191,7 @@ class TransmitterSuggestionAdmin(admin.ModelAdmin):
@admin.register(Transmitter)
class TransmitterAdmin(admin.ModelAdmin):
"""Defines Transmitter view in django admin UI"""
list_display = (
'uuid', 'description', 'satellite', 'service', 'type', 'mode', 'baud', 'downlink_low',
'downlink_high', 'downlink_drift', 'uplink_low', 'uplink_high', 'uplink_drift', 'status',
@ -167,13 +210,20 @@ class TransmitterAdmin(admin.ModelAdmin):
@admin.register(Telemetry)
class TelemetryAdmin(admin.ModelAdmin):
"""Defines Telemetry view in django admin UI"""
list_display = ('name', 'decoder')
@admin.register(DemodData)
class DemodDataAdmin(admin.ModelAdmin):
"""Defines DemodData view in django admin UI"""
list_display = ('id', 'satellite', 'app_source', 'observer')
search_fields = ('transmitter__uuid', 'satellite__norad_cat_id', 'observer')
def satellite(self, obj):
"""Returns the Satellite object associated with this DemodData
:param obj: DemodData object
:returns: Satellite object
"""
return obj.satellite

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django context processors"""
from __future__ import absolute_import, division, print_function, \
unicode_literals

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django base Forms class"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -9,7 +10,9 @@ from db.base.models import Transmitter, TransmitterEntry
class TransmitterEntryForm(forms.ModelForm):
"""Model Form class for TransmitterEntry objects"""
def existing_uuid(value):
"""ensures the UUID is existing and valid"""
try:
Transmitter.objects.get(uuid=value)
except Transmitter.DoesNotExist:

View File

@ -1,3 +1,4 @@
"""Helper functions for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -9,6 +10,13 @@ LOWER = 'abcdefghijklmnopqrstuvwx'
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:
return False
if not -90 <= lat < 90:
@ -38,6 +46,11 @@ def gridsquare(lat, lng):
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:
token = Token.objects.get(user=user)
except Exception:
@ -45,7 +58,9 @@ def get_apikey(user):
return token
# TODO: remove
def cache_get_key(*args, **kwargs):
"""Unused, needs removing"""
import hashlib
serialise = []
for arg in args:
@ -57,9 +72,13 @@ def cache_get_key(*args, **kwargs):
return key
# TODO: remove
def cache_for(time):
"""Unused, needs removing"""
def decorator(func):
"""Unused, needs removing"""
def wrapper(*args, **kwargs):
"""Unused, needs removing"""
key = cache_get_key(func.__name__, *args, **kwargs)
result = cache.get(key)
if not result:

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django management command to delete satellites"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -7,6 +8,7 @@ from db.base.models import Satellite
class Command(BaseCommand):
"""django management command to delete satellites"""
help = 'Delete selected Satellites'
def add_arguments(self, parser):

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django management command to fetch data (TLEs, etc)"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -13,6 +14,7 @@ from db.base.models import DemodData, Satellite, TransmitterEntry
class Command(BaseCommand):
"""django management command to fetch data (TLEs, etc)"""
help = 'Fetch Satellite data from Network'
def handle(self, *args, **options):

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django management command to fetch satellites"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -7,6 +8,7 @@ from db.base.tasks import update_satellite
class Command(BaseCommand):
"""django management command to fetch satellites"""
help = 'Updates/Inserts Name for certain Satellites'
def add_arguments(self, parser):

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django management command to initialize a new database"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -6,6 +7,7 @@ from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""django management command to initialize a new database"""
help = 'Create initial fixtures'
def handle(self, *args, **options):

View File

@ -1,3 +1,4 @@
"""SatNOGS DB django management command to update TLE entries"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -7,6 +8,7 @@ from db.base.tasks import update_all_tle
class Command(BaseCommand):
"""django management command to update TLE entries"""
help = 'Update TLEs for existing Satellites'
def handle(self, *args, **options):

View File

@ -1,3 +1,4 @@
"""Django database model for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -33,6 +34,11 @@ SERVICE_TYPE = [
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()
folder = 'payload_frames/{0}/{1}/{2}/'.format(today.year, today.month, today.day)
ext = 'raw'
@ -53,11 +59,13 @@ def _gen_observer(sender, instance, created, **kwargs):
def _set_is_decoded(sender, instance, **kwargs):
"""Returns true if payload_decoded has data"""
instance.is_decoded = instance.payload_decoded != ''
@python_2_unicode_compatible
class Mode(models.Model):
"""A satellite transmitter RF mode. For example: FM"""
name = models.CharField(max_length=10, unique=True)
def __str__(self):
@ -84,9 +92,17 @@ class Satellite(models.Model):
ordering = ['norad_cat_id']
def get_description(self):
"""Returns the markdown-processed satellite description
:returns: the markdown-processed satellite description
"""
return markdown(self.description)
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'):
return self.image.url
else:
@ -94,20 +110,39 @@ class Satellite(models.Model):
@property
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')
# TODO: rename this to sound more like a count
@property
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()
return pending
# TODO: rename this to sound more like a count
@property
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()
return has_data
# TODO: rename this to sound more like a count
@property
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()
return has_decoders
@ -164,11 +199,18 @@ class TransmitterEntry(models.Model):
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):
"""Returns TransmitterEntries that have not been reviewed"""
return TransmitterEntry.objects.filter(reviewed=False)
class TransmitterSuggestion(TransmitterEntry):
"""TransmitterSuggestion is an unreviewed TransmitterEntry object"""
objects = TransmitterSuggestionManager()
class Meta:
@ -177,7 +219,14 @@ class TransmitterSuggestion(TransmitterEntry):
class TransmitterManager(models.Manager):
"""Django Manager for Transmitter objects"""
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(
reviewed=True, approved=True
).filter(uuid=OuterRef('uuid')).order_by('-created')
@ -187,6 +236,9 @@ class TransmitterManager(models.Manager):
class Transmitter(TransmitterEntry):
"""Associates a generic Transmitter object with their TransmitterEntries
that are managed by TransmitterManager
"""
objects = TransmitterManager()
class Meta:
@ -195,7 +247,7 @@ class Transmitter(TransmitterEntry):
@python_2_unicode_compatible
class Telemetry(models.Model):
"""Model for satellite telemtry decoders."""
"""Model for satellite telemetry decoders."""
satellite = models.ForeignKey(
Satellite, null=True, related_name='telemetries', on_delete=models.SET_NULL
)
@ -244,13 +296,24 @@ class DemodData(models.Model):
def __str__(self):
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):
"""Returns the contents of payload_decoded
:returns: json-formatted contents of payload_decoded
"""
try:
json.dumps(self.payload_decoded)
except Exception:
'{}'
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:
with open(self.payload_frame.path) as frame_file:
return frame_file.read()

View File

@ -1,3 +1,4 @@
"""SatNOGS DB Celery task functions"""
from __future__ import absolute_import, division, print_function, \
unicode_literals

View File

@ -1,3 +1,4 @@
"""Django template tags for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -10,6 +11,7 @@ register = template.Library()
@register.simple_tag
def active(request, urls):
"""Returns if this is an active URL"""
if request.path in (reverse(url) for url in urls.split()):
return 'active'
return None
@ -17,6 +19,7 @@ def active(request, urls):
@register.filter
def frq(value):
"""Returns Hz formatted frequency html string"""
try:
to_format = float(value)
except (TypeError, ValueError):

View File

@ -1,3 +1,4 @@
"""SatNOGS DB test suites"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -18,6 +19,7 @@ DATA_SOURCE_IDS = [c[0] for c in DATA_SOURCES]
def generate_payload():
"""Create data payloads"""
payload = '{0:b}'.format(random.randint(500000000, 510000000))
digits = 1824
while digits:
@ -28,6 +30,7 @@ def generate_payload():
def generate_payload_name():
"""Create payload names"""
filename = datetime.strftime(
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():
"""Returns valid satellites"""
qs = Transmitter.objects.all()
satellites = Satellite.objects.filter(transmitters__in=qs).distinct()
return satellites
@ -89,6 +93,7 @@ class TransmitterFactory(factory.django.DjangoModelFactory):
class TransmitterSuggestionFactory(factory.django.DjangoModelFactory):
"""TransmitterSuggestion model factory."""
description = fuzzy.FuzzyText()
status = fuzzy.FuzzyChoice(choices=['active', 'inactive', 'invalid'])
type = fuzzy.FuzzyChoice(choices=['Transmitter', 'Transceiver', 'Transponder'])
@ -111,6 +116,7 @@ class TransmitterSuggestionFactory(factory.django.DjangoModelFactory):
class TelemetryFactory(factory.django.DjangoModelFactory):
"""Telemetry model factory."""
satellite = factory.SubFactory(SatelliteFactory)
name = fuzzy.FuzzyText()
schema = '{}'
@ -121,6 +127,7 @@ class TelemetryFactory(factory.django.DjangoModelFactory):
class DemodDataFactory(factory.django.DjangoModelFactory):
"""DemodData model factory."""
satellite = factory.SubFactory(SatelliteFactory)
transmitter = factory.SubFactory(TransmitterFactory)
app_source = fuzzy.FuzzyChoice(choices=DATA_SOURCE_IDS)
@ -144,6 +151,7 @@ class HomeViewTest(TestCase):
"""
def test_home_page(self):
"""Tests for a known string in the SatNOGS DB home page template"""
response = self.client.get('/')
self.assertContains(response, 'SatNOGS DB is, and will always be, an open database.')
@ -160,6 +168,7 @@ class SatelliteViewTest(TestCase):
self.satellite.save()
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)
self.assertContains(response, self.satellite.name)
@ -171,6 +180,7 @@ class AboutViewTest(TestCase):
"""
def test_about_page(self):
"""Tests for a known string in the SatNOGS DB about page template"""
response = self.client.get('/about/')
self.assertContains(response, 'SatNOGS DB is an effort to create an hollistic')
@ -182,5 +192,6 @@ class FaqViewTest(TestCase):
"""
def test_faq_page(self):
"""Tests for a known string in the SatNOGS DB FAQ page template"""
response = self.client.get('/faq/')
self.assertContains(response, 'How do I suggest a new transmitter?')

View File

@ -1,3 +1,4 @@
"""Django base URL routings for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals

View File

@ -1,3 +1,4 @@
"""Miscellaneous functions for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -19,7 +20,10 @@ LOGGER = logging.getLogger('db')
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()
transmitters = Transmitter.objects.all()
modes = Mode.objects.all()
@ -140,7 +144,10 @@ def calculate_statistics():
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 = [
{
'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):
"""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)
if sat.has_telemetry_decoders:
now = datetime.utcnow()
@ -241,6 +253,10 @@ def decode_data(norad, period=None):
# Caches stats about satellites and data
def cache_statistics():
"""Populate a django cache with statistics from data in DB
.. seealso:: calculate_statistics
"""
statistics = calculate_statistics()
cache.set('stats_transmitters', statistics, 60 * 60 * 2)

View File

@ -1,3 +1,4 @@
"""Base django views for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -29,7 +30,10 @@ LOGGER = logging.getLogger('db')
def home(request):
"""View to render home page."""
"""View to render home page.
:returns: base/home.html
"""
satellites = Satellite.objects.all()
transmitter_suggestions = TransmitterSuggestion.objects.count()
contributors = User.objects.filter(is_active=1).count()
@ -51,23 +55,36 @@ def home(request):
def custom_404(request):
"""Custom 404 error handler."""
"""Custom 404 error handler.
:returns: 404.html
"""
return HttpResponseNotFound(render(request, '404.html'))
def custom_500(request):
"""Custom 500 error handler."""
"""Custom 500 error handler.
:returns: 500.html
"""
return HttpResponseServerError(render(request, '500.html'))
def robots(request):
"""robots.txt handler
:returns: robots.txt
"""
data = render(request, 'robots.txt', {'environment': settings.ENVIRONMENT})
response = HttpResponse(data, content_type='text/plain; charset=utf-8')
return response
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)
transmitter_suggestions = TransmitterSuggestion.objects.filter(satellite=satellite)
for transmitter_suggestion in transmitter_suggestions:
@ -108,7 +125,13 @@ def satellite(request, norad):
@login_required
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)
messages.success(
request, ('Your download request was received. '
@ -120,7 +143,10 @@ def request_export(request, norad, period=None):
@login_required
@require_POST
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)
if transmitter_form.is_valid():
transmitter = transmitter_form.save(commit=False)
@ -175,17 +201,28 @@ def transmitter_suggestion(request):
def about(request):
"""View to render about page."""
"""View to render about page.
:returns: 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):
"""View to render faq page."""
"""View to render faq page.
:returns: base/faq.html
"""
return render(request, 'base/faq.html')
def stats(request):
"""View to render stats page."""
"""View to render stats page.
:returns: base/stats.html
"""
satellites = cache.get('stats_satellites')
observers = cache.get('stats_observers')
# TODO this will never succeed, cache_statistics() runs too long to be live
@ -198,6 +235,10 @@ def stats(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')
if not statistics:
cache_statistics()
@ -205,8 +246,12 @@ def statistics(request):
return JsonResponse(statistics, safe=False)
# TODO: this is confusing as we call it "edit" but it is the users "settings"
@login_required
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)
return render(request, 'base/users_edit.html', {'token': token})

View File

@ -1,3 +1,4 @@
"""SatNOGS DB celery task workers"""
from __future__ import absolute_import, division, print_function, \
unicode_literals
@ -20,6 +21,7 @@ APP.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@APP.on_after_finalize.connect
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
sender.add_periodic_task(RUN_DAILY, update_all_tle.s(), name='update-all-tle')

View File

@ -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, \
unicode_literals

View File

@ -1,3 +1,4 @@
""" Base Django URL mapping for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
"""WSGI module for SatNOGS DB"""
from __future__ import absolute_import, division, print_function, \
unicode_literals