diff --git a/.travis.yml b/.travis.yml index e835ca41..c660dccc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,4 +30,4 @@ install: before_script: - python manage.py migrate --noinput script: - - python -W ignore manage.py test -v 2 + - python -W ignore manage.py test -v 2 diff --git a/sesh/settings.py b/sesh/settings.py index d872f918..8cd86246 100644 --- a/sesh/settings.py +++ b/sesh/settings.py @@ -431,6 +431,5 @@ # Sesh Settings -SESH_REPORT_TABLES = [ - 'Daily_Data_Point', -] +# The report tables are used to allow report generation for sesh models +SESH_REPORT_TABLES = [] diff --git a/seshdash/admin.py b/seshdash/admin.py index a40c75b6..9b06862e 100644 --- a/seshdash/admin.py +++ b/seshdash/admin.py @@ -88,6 +88,10 @@ class SensorMapping(GuardedModelAdmin): class ReportDisplay(GuardedModelAdmin): pass +@admin.register(Tick_Script) +class TickScript(GuardedModelAdmin): + pass + @admin.register(Report_Sent) class ReportSentDisplay(GuardedModelAdmin): list_display = ('report_job', 'date', 'title', 'status') diff --git a/seshdash/data/db/influx.py b/seshdash/data/db/influx.py index eee4a4fe..05841dfb 100644 --- a/seshdash/data/db/influx.py +++ b/seshdash/data/db/influx.py @@ -346,6 +346,18 @@ def get_measurement_range_bucket(self, measurement_name, start, end, group_by, s results = list(self._influx_client.query(query, database=db).get_points()) return results + def drop_measurement(self, measurement_name, database=None): + """ + Deletes a measurement from the influx db + """ + db = self.db + if database: + db = database + + query = "DROP MEASUREMENT %s" % (measurement_name) + + results = list(self._influx_client.query(query, database=db).get_points()) + return results # Helper classes to the interface diff --git a/seshdash/data/db/kapacitor.py b/seshdash/data/db/kapacitor.py index 76e34ce6..f9e8f931 100644 --- a/seshdash/data/db/kapacitor.py +++ b/seshdash/data/db/kapacitor.py @@ -195,14 +195,18 @@ def get_task(self, task_id ): return re[1] - def list_tasks(self): + def list_tasks(self, pattern=''): """ List the current tasks in kapacitor + @param pattern - This specifies a pattern to query kapacitor with, Note: it uses shell global matching syntax """ - data_dict = {} + data_dict = { + 'pattern': pattern, + } re = self._make_request('tasks', type_of_request = 'GET', + data = data_dict, ) logger.debug("got response %s %s" % re) @@ -231,9 +235,34 @@ def update_task(self, task_id ): return re[1] + def set_task_status(self, task_id, status): + """ + Sets the status for a given task + + @param task_id - The task to set the status to + @param status - value to set, 'enabled' or 'disabled' + """ + path_params = { + 'task_id': task_id, + } + + data = { + 'status': status, + } + + re = self._make_request('get_tasks', + type_of_request = 'PATCH', + path_params = path_params, + data = data + ) + + logger.debug("got response %s %s"%re) + return re[1] + - def delete_task(self, task_id ): + + def delete_task(self, task_id): """ Delete a created task @@ -254,6 +283,31 @@ def delete_task(self, task_id ): return re[1] + def delete_tasks(self, pattern): + """ + Deletes tasks matching a specific pattern, + + @param pattern - specifies a shell glob mapping pattern + """ + tasks = self.list_tasks(pattern=pattern) + + for task in tasks["tasks"]: + self.delete_task(task['id']) + + return True + + def delete_all_tasks(self): + """ + Delete all the tasks in kapacitor + """ + tasks = self.list_tasks() + + for task in tasks["tasks"]: + self.delete_task(task['id']) + + return True + + def create_recording(self, task_id, stop, method='stream', id=None): """ Creates a kapacitor recording diff --git a/seshdash/migrations/0004_tick_script.py b/seshdash/migrations/0004_tick_script.py new file mode 100644 index 00000000..4da1aa09 --- /dev/null +++ b/seshdash/migrations/0004_tick_script.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.1 on 2016-12-21 15:25 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('seshdash', '0003_auto_20161212_1209'), + ] + + operations = [ + migrations.CreateModel( + name='Tick_Script', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('input_field_name', models.CharField(max_length=40)), + ('output_field_name', models.CharField(max_length=40)), + ('script', models.TextField()), + ('function', models.CharField(max_length=20)), + ('interval', models.CharField(max_length=10)), + ('type', models.CharField(choices=[(b'stream', b'Stream'), (b'batch', b'Batch')], max_length=10)), + ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='seshdash.Sesh_Site')), + ], + ), + ] diff --git a/seshdash/migrations/0005_auto_20161222_1026.py b/seshdash/migrations/0005_auto_20161222_1026.py new file mode 100644 index 00000000..bda44166 --- /dev/null +++ b/seshdash/migrations/0005_auto_20161222_1026.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.1 on 2016-12-22 08:26 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('seshdash', '0004_tick_script'), + ] + + operations = [ + migrations.RenameField( + model_name='tick_script', + old_name='type', + new_name='script_type', + ), + ] diff --git a/seshdash/migrations/0009_merge.py b/seshdash/migrations/0009_merge.py new file mode 100644 index 00000000..a0d72374 --- /dev/null +++ b/seshdash/migrations/0009_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.1 on 2017-01-26 09:19 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('seshdash', '0005_auto_20161222_1026'), + ('seshdash', '0008_auto_20170125_1352'), + ] + + operations = [ + ] diff --git a/seshdash/migrations/0010_auto_20170126_1401.py b/seshdash/migrations/0010_auto_20170126_1401.py new file mode 100644 index 00000000..c27617b4 --- /dev/null +++ b/seshdash/migrations/0010_auto_20170126_1401.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.1 on 2017-01-26 12:01 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('seshdash', '0009_merge'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='report_job', + unique_together=set([('site', 'duration')]), + ), + ] diff --git a/seshdash/models.py b/seshdash/models.py index e1a7fff0..e87c383d 100644 --- a/seshdash/models.py +++ b/seshdash/models.py @@ -14,6 +14,8 @@ from django_mysql.models import JSONField +from seshdash.data.db.kapacitor import Kapacitor + # Create your models here. class VRM_Account(models.Model): """ @@ -695,6 +697,45 @@ def get_duration_choices(self): return duration_list + def get_kapacitor_tasks(self): + kap = Kapacitor() + pattern = self.site.site_name + '_' + self.duration + "*" + return kap.list_tasks(pattern=pattern) + + def save(self, *args, **kwargs): + """ + On save add kapacitor task referencing the report + """ + self.add_kapacitor_tasks() + super(Report_Job, self).save(*args, **kwargs) + + def add_kapacitor_tasks(self): + """ + Adds the kapacitor tasks for the report + """ + from seshdash.utils.reporting import add_report_kap_tasks + add_report_kap_tasks(self) + + def delete(self, *args, **kwargs): + """ + On delete delet kapacitor tasks referencing the report Job + """ + self.delete_kapacitor_tasks() + super(Report_Job, self).delete(*args, **kwargs) + + + def delete_kapacitor_tasks(self): + """ + Deletes the kapacitor tasks attached to the report + """ + kap = Kapacitor() + pattern = self.site.site_name + '_' + self.duration + "*" # tasks begining with site_name_duration + return kap.delete_tasks(pattern) + + + class Meta: + unique_together = (('site','duration'),) + class Report_Sent(models.Model): """ @@ -744,3 +785,24 @@ class Data_Process_Rule(models.Model): duration = models.CharField(max_length=40, default="24h", choices=DURATION) interval = models.CharField(max_length=10, default="5m", choices=TIME_BUCKETS) output_field = models.ForeignKey(Trend_Data_Point) + + +class Tick_Script(models.Model): + """ + This is a model to hold data about the + tick scripts + """ + SCRIPT_TYPE_CHOICES = ( + ('stream', 'Stream'), + ('batch', 'Batch'), + ) + + site = models.ForeignKey(Sesh_Site) + input_field_name = models.CharField(max_length=40) # The influx measurement to operate on + output_field_name = models.CharField(max_length=40) # The influx measurement to output results of the operation + script = models.TextField() + function = models.CharField(max_length=20) # Influx function operation to use + interval = models.CharField(max_length=10) # The interval the task script runs on e.g 1min, 1h, 1d, 1w + script_type = models.CharField(max_length=10, choices=SCRIPT_TYPE_CHOICES) + + diff --git a/seshdash/tests/test_kapacitor.py b/seshdash/tests/test_kapacitor.py index d74eba14..d9ba3b55 100644 --- a/seshdash/tests/test_kapacitor.py +++ b/seshdash/tests/test_kapacitor.py @@ -95,6 +95,7 @@ def setUp(self): #assign a user to the sites assign_perm("view_Sesh_Site",self.test_user,self.site) + def tearDown(self): self.i.delete_database(self._influx_db_name) self.kap.delete_template(self.template_id) @@ -251,6 +252,28 @@ def test_task_dj_template(self): result = self.kap.create_task(alert_id, dbrps= self.dbrps, script=rendered_alert) self.assertEquals(result['status'], 'enabled') + def test_set_task_status(self): + """ + Testing the function that updates status + of tasks + """ + script = """ + stream + |from() + .measurement('cpu') + |alert() + .crit(lambda: "value" < 70) + .log('/tmp/alerts.log') + """ + + task = self.kap.create_task('test_task', script, status='enabled') + self.kap.set_task_status('test_task', 'disabled') + + # asserting + task = self.kap.get_task('test_task') + self.assertEqual(task['status'], 'disabled') + + diff --git a/seshdash/tests/test_reports.py b/seshdash/tests/test_reports.py index 27ad72c4..ae37c24b 100644 --- a/seshdash/tests/test_reports.py +++ b/seshdash/tests/test_reports.py @@ -11,9 +11,11 @@ from geoposition import Geoposition from seshdash.models import Daily_Data_Point, Report_Job, Sesh_Site, Sesh_Organisation, Sesh_User, Report_Sent -from seshdash.utils.reporting import send_report, generate_report_data, _format_column_str, _get_operation, get_emails_list, \ - get_table_report_dict, get_edit_report_list, is_in_report_attributes +from seshdash.utils.reporting import send_report, get_emails_list, get_edit_report_list, is_in_report_attributes,\ + _format_column_str from seshdash.tasks import check_reports +from seshdash.data.db.influx import Influx +from seshdash.data.db.kapacitor import Kapacitor class ReportTestCase(TestCase): @@ -46,81 +48,51 @@ def setUp(self): battery_bank_capacity = 1000) self.attributes_data = [ - {"table":"Daily_Data_Point", - "column":"daily_pv_yield", - "operation":"average", - "user_friendly_name":"Daily pv yield average"}, - {"table":"Daily_Data_Point", - "column":"daily_power_consumption_total", - "operation":"sum", - "user_friendly_name":"Daily power consumption total sum" - }, + {"operation": "sum", + "field": "trans", + "output_field": "sum_trans", + "user_friendly_name": "Trans sum"}, + {"operation": "mean", + "field": "relay_state", + "output_field": "mean_relay_state", + "user_friendly_name": "Relay state mean"} ] - self.daily_data_point_one = Daily_Data_Point.objects.create( - site = self.site, - date = timezone.now(), - daily_pv_yield = 10, - daily_power_consumption_total = 10, - ) - - self.daily_data_point_two = Daily_Data_Point.objects.create( - site = self.site, - date = timezone.now(), - daily_pv_yield = 10, - daily_power_consumption_total = 10, - ) self.report = Report_Job.objects.create(site=self.site, duration="daily", day_to_report=datetime.now().today().weekday(), attributes=self.attributes_data) + self.i = Influx() + self.kap = Kapacitor() - def test_models(self): - """ - Testing the models - """ - self.assertEqual(Report_Job.objects.all().count(), 1) - def test_generate_report_data(self): + def tearDown(self): """ - Testing the util that generates the report dict + Delete kap tasks for the test site """ - results = generate_report_data(self.report) - # Asserting if the aggregations are correct - self.assertTrue(results[0]['unit']) - self.assertTrue(results[0]['user_friendly_name']) - - for item in results: - if item['user_friendly_name'] == 'Daily pv yield average': - self.assertEqual(item['val'], 10) + self.kap.delete_tasks(pattern="test_site*") + - def test_send_reports(self): + def test_models(self): """ - Testing the task that send reports + Testing the models """ - reported_reports = check_reports() - self.assertEqual(reported_reports, 1) + self.assertEqual(Report_Job.objects.all().count(), 1) def test_send_report(self): """ Testing the sending of the generated reports, Test logging of report """ - val = send_report(self.report) + #val = send_report(self.report) - report_log = Report_Sent.objects.all() - self.assertTrue(val) - self.assertGreater(len(report_log),0) + #report_log = Report_Sent.objects.all() + #self.assertTrue(val) + #self.assertGreater(len(report_log),0) + print "the sending of report messages" - def test__get_operation(self): - ''' - Testing _get_operation function that takes - an attribute and returns a function to execute - ''' - val = _get_operation(self.attributes_data[0]) - self.assertEqual(val, Avg) def test__format_column_str(self): """ @@ -138,19 +110,6 @@ def test_get_email_users(self): mail_list = get_emails_list([self.test_user]) self.assertEqual(mail_list, ['test@gle.solar']) - def tests_get_table_report_dict(self): - """ - Testing the function that takes a table and operations as input - and then returns a attribute dict that can be used to create a report - """ - report_dict = get_table_report_dict('Daily_Data_Point', 'sum') - self.assertEqual(report_dict[0]['operation'], 'sum') - self.assertEqual(report_dict[0]['table'], 'Daily_Data_Point') - - # Should raise a lookup error in case of incorrect table input - with self.assertRaises(LookupError): - get_table_report_dict('UnknownTable', 'sum') - def test_add_report(self): """ Testing the adding of the reports from @@ -158,9 +117,18 @@ def test_add_report(self): """ # The below is the format of the data that is received from a client when adding a report data = { - '{"table":"Daily_Data_Point","column":"daily_pv_yield","operation":"average","user_friendly_name":"Daily pv yield average"}': ['on'], - '{"table":"Daily_Data_Point","column":"daily_power_consumption_total","operation":"sum","user_friendly_name":"Daily power consumption sum"}': ['on'], + 'duration': 'weekly', + + '{"operation": "sum", \ + "field": "trans", \ + "output_field": "sum_trans", \ + "user_friendly_name": "Trans sum"}': ['on'], + + '{"operation": "mean", \ + "field": "relay_state", \ + "output_field": "mean_relay_state", \ + "user_friendly_name": "Relay state mean"}': ['on'], } self.client.login(username='test_user', password='test.test.test') @@ -174,10 +142,21 @@ def test_delete_report(self): Testing the deletion of a report """ self.client.login(username='test_user', password='test.test.test') + + # checkinf if there tasks in kapacitor + kap_tasks = self.kap.list_tasks() + self.assertNotEqual(len(kap_tasks["tasks"]), 0) + + + # deleting the tasks response = self.client.get(reverse('delete_report', args=[self.report.id])) self.assertEqual(response.status_code, 302) # Testing the redirection to manage reports page for site + # Checking if the tasks and the report deleted after the report is deleted self.assertEqual(Report_Job.objects.all().count(), 0) + kap_tasks = self.kap.list_tasks() + self.assertEqual(len(kap_tasks["tasks"]), 0) + def test_is_in_report_attributes(self): """ @@ -194,6 +173,10 @@ def test_get_edit_report_list(self): The function returns a dict, which has status on for each active attribute and off otherwise """ + # Creating measurements to the influx db + self.i.insert_point(site=self.site, measurement_name='trans', value=0) + self.i.insert_point(site=self.site, measurement_name='relay_state', value=0) + report_dict = get_edit_report_list(self.report) count = 0 @@ -210,15 +193,16 @@ def test_edit_report(self): """ self.client.login(username='test_user', password='test.test.test') data = { - '{"table":"Daily_Data_Point", "column":"daily_pv_yield","operation":"average","user_friendly_name":"Daily pv yield average"}' - - : ['on'], - 'duration': 'monthly', + '{"operation": "sum", \ + "field": "trans", \ + "output_field": "sum_trans", \ + "user_friendly_name": "Trans sum"}': ['on'], + 'duration': 'weekly', } response = self.client.post(reverse('edit_report', args=[self.report.id]), data) self.assertEqual(response.status_code, 302) # The rediction to the manage reports report = Report_Job.objects.filter(id=self.report.id).first() - self.assertEqual(report.duration, 'monthly') + self.assertEqual(report.duration, 'weekly') self.assertEqual(len(report.attributes), 1) diff --git a/seshdash/utils/reporting.py b/seshdash/utils/reporting.py index c9df08d9..1b9ae8d6 100644 --- a/seshdash/utils/reporting.py +++ b/seshdash/utils/reporting.py @@ -1,12 +1,16 @@ from seshdash.models import Sesh_Site,Site_Weather_Data,BoM_Data_Point, Alert_Rule, Sesh_Alert,Daily_Data_Point, Sesh_User, Report_Sent from seshdash.utils.send_mail import send_mail from seshdash.utils.model_tools import get_measurement_unit +from seshdash.data.db.kapacitor import Kapacitor +from seshdash.data.db.influx import Influx from django.forms.models import model_to_dict from django.utils import timezone from django.db.models import Avg, Sum from django.apps import apps from django.core.exceptions import FieldError +from django.conf import settings +from django.template.loader import get_template from guardian.shortcuts import get_users_with_perms from datetime import datetime @@ -23,6 +27,9 @@ def send_report(report): """ Sends report to the users with activated report permission on the site + """ + # Function to send the report when given data + """ report_data = generate_report_data(report) users = Sesh_User.objects.filter(organisation=report.site.organisation, send_mail=True) #users with emailreport on in the organisation @@ -51,60 +58,20 @@ def send_report(report): report.save() return val - -def generate_report_data(report): """ - Function to generate a report, - The function receives a report model instance and - it returns a dict containing the aggregated value of the - report attributes - """ - report_data = [] - now = datetime.now() - - # Getting the correct date range - if report.duration == "daily": - start = now - relativedelta(hours=24) - elif report.duration == "weekly": - start = now - relativedelta(weeks=1) - elif report.duration == "monthly": - start = now - relativedelta(months=1) - - - # Getting the aggregation of the values in the report attributes - for attribute in report.attributes: - operation = _get_operation(attribute) # Getting the operation to execute, average or sum - - try: - table = apps.get_model(app_label="seshdash", model_name=attribute["table"]) - except LookupError: - raise Exception("ERROR IN REPORTS: Incorrect table name in the report jsonfield") - - try: - data = table.objects.filter(site=report.site, - date__range=[start, now]).aggregate(val = operation(attribute["column"])) - except FieldError: - raise Exception("ERROR IN REPORTS: Incorrect column name in the jsonfield") - - data["user_friendly_name"] = _format_column_str(attribute["column"]) + " " + attribute["operation"] - data["unit"] = get_measurement_unit(attribute["column"]) - report_data.append(data) + print "Modify the function to work with influx data" - return report_data -def _get_operation(attribute): +def get_emails_list(users): """ - Function to return the operation to be used - when aggregating data for a report attribute + Returns a list of emails from the users """ - if attribute['operation'] == "average": - operation = Avg - elif attribute['operation'] == "sum": - operation = Sum - else: - raise Exception("Invalid opperation in attribute for report") + emails = [] + + for user in users: + emails.append(user.email) - return operation + return emails def _format_column_str(string): @@ -118,32 +85,32 @@ def _format_column_str(string): mod = mod + ' ' else: mod = mod + letter - return mod.capitalize() + return mod.capitalize() -def get_emails_list(users): +def get_report_attributes(): """ - Returns a list of emails from the users + Returns the report attributes for sesh report tables found in settings. """ - emails = [] + i = Influx() + measurements = i.get_measurements() + attributes = [] + operations = ['sum', 'mean'] - for user in users: - emails.append(user.email) + for measurement in measurements: + if measurement['name'] != 'site': + for operation in operations: + dict = {} + dict['field'] = str(measurement['name']) + dict['output_field'] = str(operation + '_' + measurement['name']) + dict['operation'] = str(operation) + dict['user_friendly_name'] = str(_format_column_str(measurement['name']) + ' ' + operation) + attributes.append(dict) - return emails + return attributes -def get_report_table_attributes(): - """ - Returns the report attributes for sesh report tables - found in settings - """ - from django.conf import settings - attributes = [] - for table_name in settings.SESH_REPORT_TABLES: - attributes.extend(get_table_report_dict(table_name, ['sum', 'average'])) - return attributes def get_report_instance_attributes(report): @@ -170,9 +137,10 @@ def get_edit_report_list(report): Returns a list that represents the status of items in the report compared to what can be in the reports """ - possible_attributes = get_report_table_attributes() + possible_attributes = get_report_attributes() data_list = [] + for attribute in possible_attributes: data_dict = {} if is_in_report_attributes(attribute, report): @@ -183,6 +151,7 @@ def get_edit_report_list(report): data_dict['report_value'] = attribute data_list.append(data_dict) + print "The returned data list is: %s" % data_list return data_list def is_in_report_attributes(dictionary, report): @@ -200,28 +169,59 @@ def is_in_report_attributes(dictionary, report): return False -def get_table_report_dict(report_table_name, operations): + +""" +Kapacitor report utils +""" +def add_report_kap_tasks(report): + """ + This function adds tasks for a report to kapacitor + @param report - The report instance in the database """ - Returns a dict containing all the reporting values - possible for models containing reporting data + kap = Kapacitor() + t = get_template('seshdash/kapacitor_tasks/aggregate_report.tick') + attributes = report.attributes + + for attribute in attributes: + data = { + 'database': settings.INFLUX_DB, + 'operation': attribute['operation'], + 'field': attribute['field'], + 'output_field': attribute['output_field'], + 'duration': '1m', + 'site_id': report.site.id, + } + + task_name = str(report.site.site_name + '_' + report.duration + '_' + attribute['operation'] + '_' + attribute['field']) + dbrps = [{"db": settings.INFLUX_DB, "rp": "autogen"}] + response = kap.create_task(task_name, t.render(data), task_type='batch', dbrps=dbrps) + + return True - @param report_table_name: Ex Daily_Data_Point - @param operations: 'sum' or 'average' or ['sum', 'average'] + +def disable_report_tasks(report): """ - operations = operations if isinstance(operations, list) else [operations] # Converting any item that is not a list ot a list - table = apps.get_model(app_label="seshdash", model_name=report_table_name) + This disables the report tasks for a given instance + @param report = The report instance to user + """ + kap = Kapacitor() + tasks = report.get_kapacitor_tasks() + + for task in tasks["tasks"]: + kap.set_task_status(task['id'], 'disabled') + + return True - report_table_attributes = [] - fields = table._meta.fields +def enable_report_tasks(report): + """ + This enables the report tasks that are disabled for a report + @param reprot - The report instance to use + """ + kap = Kapacitor() + attributes = report.attributes - for operation in operations: - for field in fields: - if field.name != 'site' and field.name != 'id' and field.name != 'date': - report_attribute_dict = {} - report_attribute_dict['column'] = field.name - report_attribute_dict['table'] = report_table_name - report_attribute_dict['operation'] = operation - report_attribute_dict['user_friendly_name'] = _format_column_str(field.name) + ' ' + operation - report_table_attributes.append(report_attribute_dict) + for attribute in attributes: + task_name = str(report.site.site_name + '_' + report.duration + '_' + attribute['operation'] + '_' + attribute['field']) + response = kap.set_task_status(task_name, 'enabled') - return report_table_attributes + return True diff --git a/seshdash/views.py b/seshdash/views.py index e5fa9915..9420560b 100644 --- a/seshdash/views.py +++ b/seshdash/views.py @@ -43,7 +43,7 @@ get_measurement_verbose_name, get_measurement_unit,get_status_card_items,get_site_measurements, \ associate_sensors_sets_to_site, get_all_associated_sensors, get_config_sensors, save_sensor_set, model_list_to_field_list -from seshdash.utils.reporting import get_report_table_attributes, get_edit_report_list +from seshdash.utils.reporting import get_report_attributes, get_edit_report_list, disable_report_tasks, enable_report_tasks from seshdash.models import SENSORS_LIST from datetime import timedelta @@ -1292,27 +1292,30 @@ def manage_reports(request, site_id): @login_required def add_report(request, site_id): """ - View to help in managing the reports + View to add a report instance for a site. + @param site_id - Site id of the current site """ site = Sesh_Site.objects.filter(id=site_id).first() context_dict = {} - context_dict['report_attributes'] = get_report_table_attributes() + context_dict['report_attributes'] = get_report_attributes() attributes = [] # if the user does not belong to the organisation or if the user is not an admin - if not(request.user.organisation == site.organisation and request.user.is_org_admin): + if request.user.organisation != site.organisation or request.user.is_org_admin != True: return HttpResponseForbidden() if request.method == "POST": # Getting all the checked report attribute values + key, value = request.POST.items()[0] for key, value in request.POST.items(): if value == 'on': attributes.append(demjson.decode(key)) - Report_Job.objects.create(site=site, + report = Report_Job.objects.create(site=site, attributes=attributes, duration=request.POST.get('duration', 'daily'), day_to_report=0) + return redirect(reverse('manage_reports', args=[site.id])) return render(request, 'seshdash/settings/add_report.html', context_dict) @@ -1335,6 +1338,11 @@ def edit_report(request, report_id): report.attributes = attribute_list report.duration = request.POST['duration'] + + # Editing the kapacitor tasks + disable_report_tasks(report) + enable_report_tasks(report) + report.save() return redirect(reverse('manage_reports', args=[report.site.id])) diff --git a/templates/seshdash/kapacitor_tasks/aggregate_report.tick b/templates/seshdash/kapacitor_tasks/aggregate_report.tick new file mode 100644 index 00000000..4b38d385 --- /dev/null +++ b/templates/seshdash/kapacitor_tasks/aggregate_report.tick @@ -0,0 +1,24 @@ +// Example report tick script +// A user wants to get average(mean) for a field battery_voltage in a db called sesh +// The result will be outputed in a field called mean_battery_voltage in the sesh db + + +var database = '{{ database }}' + +var duration = {{ duration }} + +var output_field = '{{ output_field }}' + +var points = batch + |query(''' + SELECT {{operation}}(value) + FROM "{{database}}"."autogen"."{{ field }}" + WHERE site_id={{site_id}} + ''') + .period(duration) + .every(duration) + +points + |influxDBOut() + .database(database) + .measurement(output_field)