193 lines
5.2 KiB
Python
193 lines
5.2 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import json
|
|
|
|
from celery.schedules import crontab
|
|
from djcelery.models import PeriodicTask
|
|
|
|
from mayan.celery import app
|
|
|
|
from .models import StatisticResult
|
|
|
|
|
|
class StatisticNamespace(object):
|
|
_registry = {}
|
|
|
|
@classmethod
|
|
def get_all(cls):
|
|
return cls._registry.values()
|
|
|
|
@classmethod
|
|
def get(cls, slug):
|
|
return cls._registry[slug]
|
|
|
|
def __init__(self, slug, label):
|
|
self.slug = slug
|
|
self.label = label
|
|
self._statistics = []
|
|
self.__class__._registry[slug] = self
|
|
|
|
def __unicode__(self):
|
|
return unicode(self.label)
|
|
|
|
def add_statistic(self, *args, **kwargs):
|
|
statistic = Statistic(*args, **kwargs)
|
|
statistic.namespace = self
|
|
self._statistics.append(statistic)
|
|
|
|
@property
|
|
def statistics(self):
|
|
return self._statistics
|
|
|
|
|
|
class Statistic(object):
|
|
_registry = {}
|
|
|
|
@staticmethod
|
|
def purge_schedules():
|
|
queryset = PeriodicTask.objects.filter(name__startswith='statistics.').exclude(name__in=Statistic.get_task_names())
|
|
|
|
for periodic_task in queryset:
|
|
crontab_instance = periodic_task.crontab
|
|
periodic_task.delete()
|
|
|
|
if crontab_instance and not crontab_instance.periodictask_set.all():
|
|
# Only delete the interval if nobody else is using it
|
|
crontab_instance.delete()
|
|
|
|
StatisticResult.objects.filter(
|
|
slug__in=queryset.values_list('name', flat=True)
|
|
).delete()
|
|
|
|
@classmethod
|
|
def get_all(cls):
|
|
return cls._registry.values()
|
|
|
|
@classmethod
|
|
def get(cls, slug):
|
|
return cls._registry[slug]
|
|
|
|
@classmethod
|
|
def get_task_names(cls):
|
|
return [task.get_task_name() for task in cls.get_all()]
|
|
|
|
def __init__(self, slug, label, func, renderer, minute='*', hour='*', day_of_week='*', day_of_month='*', month_of_year='*'):
|
|
self.slug = slug
|
|
self.label = label
|
|
self.func = func
|
|
self.renderer = renderer
|
|
|
|
self.schedule = crontab(
|
|
minute=minute, hour=hour, day_of_week=day_of_week,
|
|
day_of_month=day_of_month, month_of_year=month_of_year,
|
|
)
|
|
|
|
app.conf.CELERYBEAT_SCHEDULE.update(
|
|
{
|
|
self.get_task_name(): {
|
|
'task': 'statistics.tasks.task_execute_statistic',
|
|
'schedule': self.schedule,
|
|
'args': (self.slug,)
|
|
},
|
|
}
|
|
)
|
|
|
|
app.conf.CELERY_ROUTES.update(
|
|
{
|
|
self.get_task_name(): {
|
|
'queue': 'statistics'
|
|
},
|
|
}
|
|
)
|
|
|
|
self.__class__._registry[slug] = self
|
|
|
|
def __unicode__(self):
|
|
return unicode(self.label)
|
|
|
|
def execute(self):
|
|
self.store_results(results=self.func())
|
|
|
|
def get_task_name(self):
|
|
return 'statistics.task_execute_statistic_{}'.format(self.slug)
|
|
|
|
def store_results(self, results):
|
|
StatisticResult.objects.filter(slug=self.slug).delete()
|
|
|
|
statistic_result, created = StatisticResult.objects.get_or_create(slug=self.slug)
|
|
statistic_result.store_data(data=results)
|
|
|
|
def get_results(self):
|
|
try:
|
|
return StatisticResult.objects.get(slug=self.slug).get_data()
|
|
except StatisticResult.DoesNotExist:
|
|
return {'series': {}}
|
|
|
|
def get_chart_data(self):
|
|
return self.renderer(data=self.get_results()).get_chart_data()
|
|
|
|
|
|
class ChartRenderer(object):
|
|
def __init__(self, data):
|
|
self.data = data
|
|
|
|
def get_chart_data(self):
|
|
raise NotImplementedError
|
|
|
|
|
|
class CharJSLine(ChartRenderer):
|
|
template_name = 'statistics/backends/chartjs/line.html'
|
|
|
|
dataset_palette = (
|
|
{
|
|
'fillColor': "rgba(220,220,220,0.2)",
|
|
'strokeColor': "rgba(220,220,220,1)",
|
|
'pointColor': "rgba(220,220,220,1)",
|
|
'pointStrokeColor': "#fff",
|
|
'pointHighlightFill': "#fff",
|
|
'pointHighlightStroke': "rgba(220,220,220,1)",
|
|
},
|
|
{
|
|
'fillColor': "rgba(151,187,205,0.2)",
|
|
'strokeColor': "rgba(151,187,205,1)",
|
|
'pointColor': "rgba(151,187,205,1)",
|
|
'pointStrokeColor': "#fff",
|
|
'pointHighlightFill': "#fff",
|
|
'pointHighlightStroke': "rgba(151,187,205,1)",
|
|
},
|
|
)
|
|
|
|
def get_chart_data(self):
|
|
labels = []
|
|
datasets = []
|
|
|
|
for count, serie in enumerate(self.data['series'].items()):
|
|
series_name, series_data = serie
|
|
dataset_labels = []
|
|
dataset_values = []
|
|
|
|
for data_point in series_data:
|
|
dataset_labels.extend(data_point.keys())
|
|
dataset_values.extend(data_point.values())
|
|
|
|
labels = dataset_labels
|
|
dataset = {
|
|
'label': series_name,
|
|
'data': dataset_values,
|
|
}
|
|
dataset.update(
|
|
CharJSLine.dataset_palette[
|
|
count % len(CharJSLine.dataset_palette)
|
|
]
|
|
)
|
|
|
|
datasets.append(dataset)
|
|
|
|
data = {
|
|
'labels': labels,
|
|
'datasets': datasets,
|
|
|
|
}
|
|
|
|
return json.dumps(data)
|