1#!/usr/bin/env python3
  2
  3"""CHART system 'activities' web page.
  4Show a summary of the currently configured Activities.
  5"""
  6
  7from io import StringIO
  8from collections import defaultdict
  9
 10from django.shortcuts import render
 11from django.urls import reverse
 12
 13from chart.project import settings
 14from chart.common.util import nvl
 15from chart.common.util import coalesce
 16from chart.common.xml import load_xml
 17from chart.common.xml import parsechildstr
 18from chart.common.xml import parsechildstrs
 19from chart.common.prettyprint import Table
 20from chart.backend.activity import Activity
 21
 22
 23def index(request):
 24    """Compile a table of all Activities, showing a trigger action,
 25    brief description and outputs of each one."""
 26
 27    scheduler = defaultdict(list)
 28    for schedule_name in settings.SCHEDULE_DIR.glob('*.xml'):
 29        schedule_elem = load_xml(schedule_name)
 30        trigger_elem = schedule_elem.find('trigger')
 31        if trigger_elem is not None:
 32            if trigger_elem.find('directory-monitor') is not None:
 33                pattern = parsechildstr(trigger_elem.find('directory-monitor'), 'pattern', None)
 34                directory = parsechildstr(trigger_elem.find('directory-monitor'), 'directory', None)
 35                if pattern is not None:
 36                    sched_type = 'File scan {pattern} in {dir}'.format(
 37                        pattern=pattern[:15], dir=directory)
 38
 39            else:
 40                sched_type = 'Schedule {n}'.format(n=schedule_name.stem)
 41
 42            # if trigger_elem.find('hourly') is not None:
 43                # sched_type = 'Hourly scheduler job'
 44
 45            # elif trigger_elem.find('daily') is not None:
 46                # sched_type = 'Daily scheduler job'
 47
 48            # elif trigger_elem.find('monthly') is not None:
 49                # sched_type = 'Monthly scheduler job'
 50
 51            # elif trigger_elem.find('weekly') is not None:
 52                # sched_type = 'Weekly scheduler job'
 53
 54            # else:
 55                # sched_type = 'Unknown scheduler job'
 56
 57            for response_elem in schedule_elem.findall('response'):
 58                for a in parsechildstrs(response_elem, 'activity'):
 59                    scheduler[a].append(sched_type)
 60
 61    res = StringIO()
 62
 63    t = Table(headings=(
 64        'Name', 'Description', 'Triggers', 'Output tables', 'Output events', 'Priority', 'Weight'),
 65              cssclass='table table-striped table-bordered')
 66    for activity in sorted(Activity.all()):
 67        if not activity.enabled:
 68            continue
 69
 70        if activity.name == 'ORBITAL_STATS':
 71            input_str = 'All timeseries tables with orbital statistics'
 72            output_str = 'All orbital stats tables'
 73            event_str = ''
 74
 75        else:
 76            input_str = ''
 77            for trigger in activity.triggers:
 78                if trigger.table is not None:
 79                    if trigger.trigger_type is not None:
 80                        trigger_type = trigger.trigger_type.value
 81
 82                    else:
 83                        trigger_type = 'direct'
 84
 85                    input_str += '<p>Table change {table} ({type})</p>'.format(
 86                        table=trigger.table.name, type=trigger_type)
 87
 88                else:
 89                    input_str += '<p>Any table</p>'
 90
 91            for sched in scheduler[activity.name]:
 92                input_str += '<p>' + sched + '</p>'
 93
 94            output_str = ''
 95            for output_table in activity.output_tables:
 96                output_str += '<p>' + output_table.name + '</p>'
 97
 98            event_str = ''.join('<p>' + e + '</p>' for e in activity.eventnames)
 99
100        if activity.name in ('PDU_INGESTER', 'SF00_INGESTER'):
101            output_str += '<p>All raw timeseries tables</p>'
102
103        name = '<a href=\'' + reverse(
104            'backend:activities/single',
105            kwargs=dict(activityname=activity.name)) + '\'>' + activity.name + '</a>'
106
107        t.append((name,
108                  nvl(activity.description),
109                  input_str,
110                  output_str,
111                  event_str,
112                  activity.priority,
113                  activity.weight))
114
115    t.write_html(res)
116
117    return render(request,
118                  'backend/activities.html',
119                  dict(table=res.getvalue()))
120
121
122def show_activity(request, activityname):
123    """A more detailed page describing a single Activity."""
124    activity = Activity(activityname)
125
126    schedule_triggers = []
127    for schedule_name in settings.SCHEDULE_DIR.glob('*.xml'):
128        schedule_elem = load_xml(schedule_name)
129        response_elem = schedule_elem.find('response')
130        match = False
131        if response_elem is not None:
132            for a in parsechildstrs(response_elem, 'activity'):
133                if a == activityname:
134                    match = True
135
136        if match:
137            trigger_elem = schedule_elem.find('trigger')
138            if trigger_elem is not None:
139                if trigger_elem.find('hourly') is not None:
140                    schedule_triggers.append('Hourly scheduler job')
141
142                elif trigger_elem.find('daily') is not None:
143                    schedule_triggers.append('Daily scheduler job')
144
145                elif trigger_elem.find('monthly') is not None:
146                    schedule_triggers.append('Monthly scheduler job')
147
148                elif trigger_elem.find('weekly') is not None:
149                    schedule_triggers.append('Weekly scheduler job')
150
151                elif trigger_elem.find('directory-monitor') is not None:
152                    pattern = parsechildstr(trigger_elem.find('directory-monitor'),
153                                            'pattern',
154                                            None)
155                    directory = parsechildstr(trigger_elem.find('directory-monitor'),
156                                              'directory',
157                                              None)
158                    if pattern is not None:
159                        schedule_triggers.append('File scan {glob} in {dir}'.format(
160                                glob=pattern[:15],
161                                dir=directory))
162
163                else:
164                    schedule_triggers.append('Unknown scheduler job')
165
166    return render(request,
167                  'backend/activity.html',
168                  dict(name=activity.name,
169                       settings=settings,
170                       activity=activity,
171                       schedule_triggers=schedule_triggers))