From 1f440dcca66281356100337a8faf9ec0e1ddce3f Mon Sep 17 00:00:00 2001
From: Mattia Mancini <mancini@astron.nl>
Date: Mon, 15 Oct 2018 12:29:05 +0000
Subject: [PATCH] OSB-28: minor fixes

---
 .../monitoringdb/models/component_error.py    |   2 +-
 .../monitoringdb/models/element_error.py      |   2 +-
 .../DBInterface/monitoringdb/models/rtsm.py   |  13 +-
 .../monitoringdb/rtsm_test_raw_parser.py      |  15 ++-
 .../monitoringdb/serializers/rtsm.py          |  48 ++++----
 .../monitoringdb/views/rtsm_views.py          |   4 +-
 .../monitoringdb/views/station_test_views.py  | 112 +++++++++++++-----
 7 files changed, 125 insertions(+), 71 deletions(-)

diff --git a/LCU/Maintenance/DBInterface/monitoringdb/models/component_error.py b/LCU/Maintenance/DBInterface/monitoringdb/models/component_error.py
index 23d2bd3cf9c..de50e7bce8a 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/models/component_error.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/models/component_error.py
@@ -9,4 +9,4 @@ class ComponentError(models.Model):
     component = models.ForeignKey(Component, on_delete=models.DO_NOTHING)
     station_test = models.ForeignKey(StationTest, on_delete=models.DO_NOTHING,
                                      related_name='component_errors')
-    details = JSONField(default={})
\ No newline at end of file
+    details = JSONField(default=dict)
\ No newline at end of file
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/models/element_error.py b/LCU/Maintenance/DBInterface/monitoringdb/models/element_error.py
index fb2e6683363..a7a14dcf547 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/models/element_error.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/models/element_error.py
@@ -12,4 +12,4 @@ class ElementError(models.Model):
                                         related_name='failing_elements')
 
     type = models.CharField(max_length=50)
-    details = JSONField(default={})
\ No newline at end of file
+    details = JSONField(default=dict)
\ No newline at end of file
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/models/rtsm.py b/LCU/Maintenance/DBInterface/monitoringdb/models/rtsm.py
index 1a63be8f95f..19c2693950f 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/models/rtsm.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/models/rtsm.py
@@ -3,7 +3,7 @@ In this file all the model regarding the real time station monitor output are co
 """
 from django.db import models
 from django.contrib.postgres.fields import ArrayField
-
+from .station import Station
 
 from .fixed_types import STATION_TYPES
 
@@ -11,11 +11,10 @@ from .fixed_types import STATION_TYPES
 class RTSMObservation(models.Model):
     observation_id = models.PositiveIntegerField(default=0)
 
-    station_name = models.CharField(max_length=6)
-    station_type = models.CharField(max_length=1, choices=STATION_TYPES)
+    station = models.ForeignKey(Station, on_delete=models.SET_NULL, null=True)
 
-    start_time = models.DateTimeField()
-    end_time = models.DateTimeField()
+    start_datetime = models.DateTimeField()
+    end_datetime = models.DateTimeField()
 
     samples = models.IntegerField(default=None, null=True)
 
@@ -24,7 +23,7 @@ class RTSMObservationSummary(RTSMObservation):
     @property
     def errors_found(self):
         return RTSMError.objects.defer('spectra'). \
-            filter(observation=self).values('error_type', 'rcu'). \
+            filter(observation=self).values('error_type', 'mode', 'rcu'). \
             annotate(count=models.Count('error_type', unique=True, output_field=models.FloatField())). \
             annotate(percentage=models.ExpressionWrapper(models.F('count') * 100. / models.F('observation__samples'),
                                                          output_field=models.FloatField()))
@@ -39,7 +38,7 @@ class RTSMError(models.Model):
     rcu = models.SmallIntegerField(default=None, null=True)
     mode = models.SmallIntegerField(default=None, null=True)
 
-    error_type = models.CharField(max_length=10)
+    error_type = models.CharField(max_length=50)
     start_frequency = models.FloatField(default=None, null=True)
     stop_frequency = models.FloatField(default=None, null=True)
     time = models.DateTimeField()
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/rtsm_test_raw_parser.py b/LCU/Maintenance/DBInterface/monitoringdb/rtsm_test_raw_parser.py
index 132b355b3a7..a6c7bf90793 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/rtsm_test_raw_parser.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/rtsm_test_raw_parser.py
@@ -1,6 +1,15 @@
 from datetime import datetime
 import pytz
 
+rtsm_error_types_to_error_types = dict(HN='HIGH_NOISE',
+                                       SN='SUMMATOR_NOISE',
+                                       CR='CABLE_REFLECTION',
+                                       LN='LOW_NOISE',
+                                       J='JITTER',
+                                       OSC='OSCILLATION',
+                                       FLAT='FLAT',
+                                       DOWN='DOWN',
+                                       SHORT='SHORT')
 
 def split_raw_rtsm_test(content):
     """
@@ -44,15 +53,15 @@ def preparse_rtsm_test_file(content):
             rcu, mode, observation_id, error_type, start_frequency, stop_frequency, time = value.split(',')
             result.update(rcu=int(rcu),
                           mode=int(mode),
-                          error_type=error_type,
+                          error_type=rtsm_error_types_to_error_types[error_type],
                           start_frequency=float(start_frequency),
                           stop_frequency=float(stop_frequency),
                           time=parse_data(time))
         elif 'INFO' in key:
             observation_id, start_time, stop_time, samples = value.split(',')
             observation.update(observation_id=int(observation_id),
-                               start_time=parse_data(start_time),
-                               end_time=parse_data(stop_time),
+                               start_datetime=parse_data(start_time),
+                               end_datetime=parse_data(stop_time),
                                samples=int(samples))
         elif 'BAD' in key:
             values = [float(item) for item in value.lstrip('[').rstrip(']').strip().split(' ')]
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/serializers/rtsm.py b/LCU/Maintenance/DBInterface/monitoringdb/serializers/rtsm.py
index e1617cf099f..035857bec45 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/serializers/rtsm.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/serializers/rtsm.py
@@ -3,8 +3,8 @@ from rest_framework import serializers
 import logging
 from django.db.transaction import atomic
 from ..exceptions import ItemAlreadyExists
-from django.db.models import ObjectDoesNotExist
 from .log import ActionLogSerializer
+from .station import Station
 
 logger = logging.getLogger('serializers')
 
@@ -56,34 +56,28 @@ class RTSMObservationSerializer(serializers.ModelSerializer):
     @atomic
     def create(self, validated_data):
         rtsm_errors = validated_data.pop('errors')
-        try:
-
-
-            # derive the station type from the station name
-            station_name = validated_data['station_name']
-            station_type = station_name[0].capitalize()
-            station_type = station_type if station_type in ['C', 'R'] else 'I'
-            validated_data.update(station_type=station_type)
-
-            # searches if the RTSM is already present
-            observation_id = validated_data['observation_id']
-            element = RTSMObservation.objects.filter(observation_id=
-                                                     observation_id,
-                                                     station_name=station_name).first()
-
-            if element is None:
-                logger.info('rtsm not found inserting %s', validated_data)
-            else:
-                logger.info('RTSM test for sas id %s started at station %s is present already. Skipping insertion',
-                            observation_id, station_name)
-                raise ItemAlreadyExists(element)
-        except ObjectDoesNotExist as e:
-            logger.info('rtsm not found inserting %s', validated_data)
 
-        RTSMObservation_instance = RTSMObservation.objects.create(**validated_data)
-        RTSMObservation_instance.save()
-        ActionLogSerializer.log_model_insert(RTSMObservation_instance)
+   # derive the station type from the station name
+        station_name = validated_data.pop('station_name')
+        station_type = station_name[0].capitalize()
+        station_type = station_type if station_type in ['C', 'R'] else 'I'
+
+        station_entry = Station.objects.filter(name=station_name).first()
+        if station_entry is None:
+            station_entry = Station(name=station_name, type=station_type).save()
+        # searches if the RTSM is already present
+        observation_id = validated_data['observation_id']
+        RTSMObservation_instance = RTSMObservation.objects.filter(observation_id=observation_id,
+                                                                  station=station_entry).first()
 
+        if RTSMObservation_instance is None:
+            logger.info('rtsm not found inserting %s', validated_data)
+            RTSMObservation_instance = RTSMObservation.objects.create(station=station_entry,
+                                                                      **validated_data)
+            RTSMObservation_instance.save()
+            ActionLogSerializer.log_model_insert(RTSMObservation_instance)
+        else:
+            raise ItemAlreadyExists(RTSMObservation_instance)
         for rtsm_error in rtsm_errors:
             rtsm_error.update(observation=RTSMObservation_instance)
 
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/views/rtsm_views.py b/LCU/Maintenance/DBInterface/monitoringdb/views/rtsm_views.py
index ae05720ce6c..660b38d0f04 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/views/rtsm_views.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/views/rtsm_views.py
@@ -65,11 +65,11 @@ def insert_raw_rtsm_test(request):
                                 entry['station_name'])
 
                 try:
-                    rtsm_item = RTSMObservationSerializer().create(entry)
+                    rtsm_item = RTSMObservationSerializer().create(dict(entry))
                     rtsm_id = rtsm_item.id
                 except ItemAlreadyExists as e:
                     return Response(status=status.HTTP_200_OK,
-                                    data='RTSM test was already inserted with id {}\n'.format(e.instance_id))
+                                    data='RTSM test was already present with id {}\n'.format(e.instance_id))
                 logger.info('RTSM inserted successfully for obsid %d and station %s',
                             entry['observation_id'],
                             entry['station_name'])
diff --git a/LCU/Maintenance/DBInterface/monitoringdb/views/station_test_views.py b/LCU/Maintenance/DBInterface/monitoringdb/views/station_test_views.py
index 511bbbd7e5d..95d17cc8cda 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/views/station_test_views.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/views/station_test_views.py
@@ -1,26 +1,29 @@
+from collections import OrderedDict
+
+import coreapi
+import coreschema
+from django.db.models import Count
 from django_filters import rest_framework as filters
-from rest_framework.viewsets import ReadOnlyModelViewSet
-from rest_framework.views import APIView
-import coreapi, coreschema
 from rest_framework.schemas import ManualSchema
-
+from rest_framework.views import APIView
+from rest_framework.viewsets import ReadOnlyModelViewSet
 
 from .common import *
 from ..models.component import Component
 from ..models.component_error import ComponentError
 from ..models.element import Element
 from ..models.element_error import ElementError
+from ..models.rtsm import RTSMObservationSummary
 from ..models.station import Station
 from ..models.station_test import StationTest
 from ..serializers.component import ComponentSerializer
-from collections import OrderedDict
 from ..serializers.component_error import ComponentErrorSerializer
 from ..serializers.element import ElementSerializer
 from ..serializers.element_error import ElementErrorSerializer
 from ..serializers.station import StationSerializer
 from ..serializers.station_tests import StationTestSerializer
 from ..station_test_raw_parser import parse_raw_station_test
-from django.db.models import Count
+
 logger = logging.getLogger('views')
 
 
@@ -73,10 +76,12 @@ class ElementErrorFilterSet(filters.FilterSet):
                                       lookup_expr='type__contains',
                                       help_text='station type')
 
-    from_date = filters.DateFilter(field_name='component_error__station_test', lookup_expr='start_datetime__gt',
+    from_date = filters.DateFilter(field_name='component_error__station_test',
+                                   lookup_expr='start_datetime__gt',
                                    help_text='select element errors from date time')
-    to_date = filters.DateFilter(field_name='component_error__station_test', lookup_expr='end_datetime__lt',
-                                   help_text='select element errors until date time')
+    to_date = filters.DateFilter(field_name='component_error__station_test',
+                                 lookup_expr='end_datetime__lt',
+                                 help_text='select element errors until date time')
 
     type = filters.CharFilter(field_name='type',
                               lookup_expr='contains', help_text='element error type')
@@ -96,7 +101,6 @@ class StationViewSet(ReadOnlyModelViewSet):
 
 
 class ComponentViewSet(ReadOnlyModelViewSet):
-
     serializer_class = ComponentSerializer
     queryset = Component.objects.all()
     filter_fields = '__all__'
@@ -164,7 +168,7 @@ def insert_raw_station_test(request):
                 return Response(exception=True,
                                 data="the post message is not correct." +
                                      " It has to be of the form \{'content':[RAWSTRING]\}: %s. Request provided %s" % (
-                                     e, request),
+                                         e, request),
                                 status=status.HTTP_400_BAD_REQUEST)
         else:
             return Response(exception=True,
@@ -181,7 +185,7 @@ class ControllerStationOverview(APIView):
     Overview of the latest tests performed on the stations
     """
 
-    DEFAULT_STATION_GROUP = 'ALL'
+    DEFAULT_STATION_GROUP = 'A'
     DEFAULT_ONLY_ERRORS = False
     DEFAULT_N_STATION_TESTS = 4
     DEFAULT_N_RTSM = 4
@@ -193,7 +197,7 @@ class ControllerStationOverview(APIView):
             required=False,
             location='query',
             schema=coreschema.Enum(['C', 'R', 'I', 'A'], description=
-                                     'Station group to select for choices are [C|R|I|ALL]',
+            'Station group to select for choices are [C|R|I|ALL]',
                                    )
         ),
         coreapi.Field(
@@ -214,20 +218,18 @@ class ControllerStationOverview(APIView):
             "errors_only",
             required=False,
             location='query',
-            schema=coreschema.Boolean(description=
-                                      'displays or not only the station with more than one error')
+            schema=coreschema.Boolean(
+                description='displays or not only the station with more than one error')
         )
     ]
     )
 
-
     def get(self, request, format=None):
-
         errors_only = request.query_params.get('errors_only', self.DEFAULT_ONLY_ERRORS)
-
         station_group = request.query_params.get('station_group', self.DEFAULT_STATION_GROUP)
-        n_station_tests = int(request.query_params.get('n_station_tests', self.DEFAULT_N_STATION_TESTS))
-        n_rtsm = request.query_params.get('n_rtsm', self.DEFAULT_N_RTSM)
+        n_station_tests = int(
+            request.query_params.get('n_station_tests', self.DEFAULT_N_STATION_TESTS))
+        n_rtsm = int(request.query_params.get('n_rtsm', self.DEFAULT_N_RTSM))
 
         station_entities = Station.objects.all()
         for group in station_group:
@@ -235,25 +237,75 @@ class ControllerStationOverview(APIView):
                 station_entities = station_entities.filter(type=group)
 
         # Since django preferes a ordered dict over a dict we make it happy... for now
-        response_payload = OrderedDict()
+        response_payload = list()
         for station_entity in station_entities:
+            station_payload = OrderedDict()
+
+            station_payload['station_name'] = station_entity.name
 
             station_test_list = StationTest.objects.filter(
-                station__name=station_entity.name).order_by('-end_datetime')[:n_station_tests-1]
-            response_payload[station_entity.name] = list()
+                station__name=station_entity.name).order_by('-end_datetime')[:n_station_tests - 1]
+            rtsm_list = RTSMObservationSummary.objects.filter(
+                station__name=station_entity.name).order_by('-end_time')[:n_rtsm - 1]
+
+            station_payload['station_tests'] = list()
             for station_test in station_test_list:
                 station_test_payload = OrderedDict()
                 component_errors = station_test.component_errors
 
-                station_test_payload['total_component_errors'] = station_test.component_errors.count()
+                station_test_payload[
+                    'total_component_errors'] = station_test.component_errors.count()
                 station_test_payload['start_datetime'] = station_test.start_datetime
                 station_test_payload['end_datetime'] = station_test.end_datetime
                 station_test_payload['checks'] = station_test.checks
-                component_errors_summary = component_errors.\
+                component_errors_summary = component_errors. \
                     values('component__type', 'type').annotate(
                     total=Count('type')).order_by('-total')
-                station_test_payload['STUFF'] = [(item['component__type'], item['type'], item['total']) for item in component_errors_summary]
-
-                response_payload[station_entity.name].append(station_test_payload)
-
-        return Response(status=status.HTTP_200_OK, data=response_payload)
\ No newline at end of file
+                component_errors_summary_dict = OrderedDict()
+                for item in component_errors_summary:
+                    item_component_type = item['component__type']
+                    item_error_type = item['type']
+                    item_error_total = item['total']
+
+                    if item_component_type not in component_errors_summary_dict:
+                        component_errors_summary_dict[item_component_type] = OrderedDict()
+
+                    component_errors_summary_dict[item_component_type][item_error_type] = \
+                        item_error_total
+                station_test_payload['component_error_summary'] = component_errors_summary_dict
+
+                station_payload['station_tests'].append(station_test_payload)
+
+            station_payload['rtsm'] = list()
+            for rtsm in rtsm_list:
+                rtsm_payload = OrderedDict()
+                rtsm_payload['observation_id'] = rtsm.observation_id
+                rtsm_payload['start_datetime'] = rtsm.start_time
+                rtsm_payload['end_datetime'] = rtsm.end_time
+
+                unique_modes = [item['mode'] for item in rtsm.errors.values('mode').distinct()]
+                rtsm_payload['mode'] = unique_modes
+                rtsm_payload['total_component_error'] = rtsm.errors_found.count()
+                from django.db.models import Window, F
+                errors_summary = OrderedDict()
+
+                errors_summary_query = rtsm.errors_found.annotate(total=
+                                                                  Window(expression=Count('rcu'),
+                                                                         partition_by=[F(
+                                                                             'error_type')])).values(
+                    'error_type', 'total').distinct()
+
+                for error_summary in errors_summary_query:
+                    errors_summary[error_summary['error_type']] = error_summary['total']
+
+                rtsm_payload['error_summary'] = errors_summary
+                station_payload['rtsm'].append(rtsm_payload)
+
+            response_payload.append(station_payload)
+        if errors_only:
+            response_payload = filter(
+                lambda station_entry:
+                len(station_entry['station_tests']) + len(station_entry['rtsm']) > 0,
+                response_payload)
+        response_payload = sorted(response_payload, key=lambda item: item['station_name'])
+        return Response(status=status.HTTP_200_OK, data=response_payload)
-- 
GitLab