Initial commit to support scheduled statistics.
This commit is contained in:
@@ -72,7 +72,7 @@ from .permissions import (
|
||||
permission_document_view
|
||||
)
|
||||
from .settings import setting_thumbnail_size
|
||||
from .statistics import DocumentStatistics, DocumentUsageStatistics
|
||||
from .statistics import document_page_count_per_month
|
||||
from .widgets import document_thumbnail
|
||||
|
||||
|
||||
@@ -351,12 +351,9 @@ class DocumentsApp(MayanAppConfig):
|
||||
|
||||
namespace = StatisticNamespace(name='documents', label=_('Documents'))
|
||||
namespace.add_statistic(
|
||||
DocumentStatistics(
|
||||
name='document_stats', label=_('Document tendencies')
|
||||
)
|
||||
)
|
||||
namespace.add_statistic(DocumentUsageStatistics(
|
||||
name='document_usage', label=_('Document usage'))
|
||||
slug='document-page-count-per-month',
|
||||
label=_('Document page count per month'),
|
||||
func=document_page_count_per_month
|
||||
)
|
||||
|
||||
post_initial_setup.connect(
|
||||
|
||||
@@ -40,15 +40,23 @@ def storage_count(path='.'):
|
||||
return total_count, total_size
|
||||
|
||||
|
||||
class DocumentStatistics(Statistic):
|
||||
def get_results(self):
|
||||
results = []
|
||||
def document_page_count_per_month():
|
||||
return (
|
||||
(
|
||||
{'August, 2015': 1244},
|
||||
{'September, 2015': 3123},
|
||||
),
|
||||
)
|
||||
|
||||
results.extend(
|
||||
[
|
||||
_('Document types: %d') % DocumentType.objects.count(),
|
||||
]
|
||||
)
|
||||
|
||||
#def get_results(self):
|
||||
# return (
|
||||
## (
|
||||
# {_('Document types'): DocumentType.objects.count()},
|
||||
# ),
|
||||
# )
|
||||
|
||||
"""
|
||||
document_stats = DocumentVersion.objects.annotate(
|
||||
page_count=Count('pages')
|
||||
).aggregate(Min('page_count'), Max('page_count'), Avg('page_count'))
|
||||
@@ -67,7 +75,7 @@ class DocumentStatistics(Statistic):
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
"""
|
||||
|
||||
class DocumentUsageStatistics(Statistic):
|
||||
def get_results(self):
|
||||
|
||||
12
mayan/apps/statistics/admin.py
Normal file
12
mayan/apps/statistics/admin.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import StatisticResult
|
||||
|
||||
|
||||
@admin.register(StatisticResult)
|
||||
class StatisticResultAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'slug', 'datetime', 'serialize_data'
|
||||
)
|
||||
@@ -1,7 +1,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from kombu import Exchange, Queue
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.celery import app
|
||||
from common import MayanAppConfig, menu_object, menu_secondary, menu_tools
|
||||
|
||||
from .classes import Statistic, StatisticNamespace
|
||||
@@ -9,6 +14,8 @@ from .links import (
|
||||
link_execute, link_namespace_details, link_namespace_list,
|
||||
link_statistics
|
||||
)
|
||||
from .literals import STATISTICS_REFRESH_INTERVAL
|
||||
from .tasks import task_check_statistics # NOQA - Force registration of task
|
||||
|
||||
|
||||
class StatisticsApp(MayanAppConfig):
|
||||
@@ -18,6 +25,32 @@ class StatisticsApp(MayanAppConfig):
|
||||
def ready(self):
|
||||
super(StatisticsApp, self).ready()
|
||||
|
||||
app.conf.CELERYBEAT_SCHEDULE.update(
|
||||
{
|
||||
'statistics.task_check_statistics': {
|
||||
'task': 'statistics.tasks.task_check_statistics',
|
||||
'schedule': timedelta(seconds=STATISTICS_REFRESH_INTERVAL),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
app.conf.CELERY_QUEUES.extend(
|
||||
(
|
||||
Queue(
|
||||
'statistics', Exchange('statistics'),
|
||||
routing_key='statistics', delivery_mode=1
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
app.conf.CELERY_ROUTES.update(
|
||||
{
|
||||
'statistics.tasks.task_check_statistics': {
|
||||
'queue': 'statistics'
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
menu_object.bind_links(links=(link_execute,), sources=(Statistic,))
|
||||
menu_object.bind_links(
|
||||
links=(link_namespace_details,), sources=(StatisticNamespace,)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .models import StatisticResult
|
||||
|
||||
|
||||
class StatisticNamespace(object):
|
||||
_registry = {}
|
||||
|
||||
@@ -18,9 +23,10 @@ class StatisticNamespace(object):
|
||||
def __unicode__(self):
|
||||
return unicode(self.label)
|
||||
|
||||
def add_statistic(self, statistic):
|
||||
self._statistics.append(statistic)
|
||||
def add_statistic(self, *args, **kwargs):
|
||||
statistic = Statistic(*args, **kwargs)
|
||||
statistic.namespace = self
|
||||
self._statistics.append(statistic)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
@@ -39,20 +45,33 @@ class Statistic(object):
|
||||
return cls._registry.values()
|
||||
|
||||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls._registry[name]
|
||||
def get(cls, slug):
|
||||
return cls._registry[slug]
|
||||
|
||||
def __init__(self, name, label):
|
||||
self.name = name
|
||||
def __init__(self, slug, label, func):
|
||||
self.slug = slug
|
||||
self.label = label
|
||||
self.__class__._registry[name] = self
|
||||
self.func = func
|
||||
self.__class__._registry[slug] = self
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.label)
|
||||
|
||||
def get_results(self, *args, **kwargs):
|
||||
return NotImplementedError
|
||||
def execute(self):
|
||||
self.store_results(results=self.func())
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.name
|
||||
return self.slug
|
||||
|
||||
def store_results(self, results):
|
||||
StatisticResult.objects.filter(slug=self.slug).delete()
|
||||
|
||||
statistic_result = StatisticResult.objects.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 StatisticResultDoesNotExist:
|
||||
return ((),)
|
||||
|
||||
3
mayan/apps/statistics/literals.py
Normal file
3
mayan/apps/statistics/literals.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
STATISTICS_REFRESH_INTERVAL = 60 * 60 # Every hour
|
||||
27
mayan/apps/statistics/migrations/0001_initial.py
Normal file
27
mayan/apps/statistics/migrations/0001_initial.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='StatisticResult',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('slug', models.SlugField(verbose_name='Slug')),
|
||||
('datetime', models.DateTimeField(auto_now=True, verbose_name='Date time')),
|
||||
('serialize_data', models.TextField(verbose_name='Data', blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Statistics result',
|
||||
'verbose_name_plural': 'Statistics results',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
||||
0
mayan/apps/statistics/migrations/__init__.py
Normal file
0
mayan/apps/statistics/migrations/__init__.py
Normal file
30
mayan/apps/statistics/models.py
Normal file
30
mayan/apps/statistics/models.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class StatisticResult(models.Model):
|
||||
slug = models.SlugField(verbose_name=_('Slug'))
|
||||
datetime = models.DateTimeField(
|
||||
auto_now=True, verbose_name=_('Date time')
|
||||
)
|
||||
serialize_data = models.TextField(blank=True, verbose_name=_('Data'))
|
||||
|
||||
def get_data(self):
|
||||
return json.loads(self.serialize_data)
|
||||
|
||||
def store_data(self, data):
|
||||
self.serialize_data = json.dumps(data)
|
||||
self.save()
|
||||
|
||||
def __str__(self):
|
||||
return self.slug
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Statistics result')
|
||||
verbose_name_plural = _('Statistics results')
|
||||
20
mayan/apps/statistics/tasks.py
Normal file
20
mayan/apps/statistics/tasks.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from mayan.celery import app
|
||||
|
||||
from .classes import StatisticNamespace
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@app.task(ignore_result=True)
|
||||
def task_check_statistics():
|
||||
logger.info('Executing')
|
||||
|
||||
for namespace in StatisticNamespace.get_all():
|
||||
for statistic in namespace.statistics:
|
||||
statistic.execute()
|
||||
|
||||
logger.info('Finshed')
|
||||
@@ -12,7 +12,7 @@ urlpatterns = patterns(
|
||||
NamespaceDetailView.as_view(), name='namespace_details'
|
||||
),
|
||||
url(
|
||||
r'^(?P<statistic_id>\w+)/execute/$', StatisticExecute.as_view(),
|
||||
r'^(?P<statistic_id>[\w,-]+)/view/$', StatisticExecute.as_view(),
|
||||
name='statistic_execute'
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user