diff options
| -rw-r--r-- | archaeological_operations/templates/ishtar/sheet_operation.html | 19 | ||||
| -rw-r--r-- | archaeological_operations/urls.py | 4 | ||||
| -rw-r--r-- | archaeological_operations/views.py | 37 | ||||
| -rw-r--r-- | archaeological_warehouse/models.py | 6 | ||||
| -rw-r--r-- | archaeological_warehouse/templates/ishtar/sheet_container.html | 22 | ||||
| -rw-r--r-- | archaeological_warehouse/templates/ishtar/sheet_warehouse.html | 19 | ||||
| -rw-r--r-- | archaeological_warehouse/urls.py | 8 | ||||
| -rw-r--r-- | archaeological_warehouse/views.py | 25 | ||||
| -rw-r--r-- | ishtar_common/models.py | 31 | 
9 files changed, 147 insertions, 24 deletions
| diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html index ef5de7f59..868040666 100644 --- a/archaeological_operations/templates/ishtar/sheet_operation.html +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -408,7 +408,24 @@      <div class="tab-pane fade" id="{{window_id}}-statistics"         role="tabpanel" aria-labelledby="{{window_id}}-statistics-tab">          <h3>{% trans "Statistics" %}</h3> -        <small class="centered"><em>{% trans "These numbers are updated hourly" %}</em></small> + +        <div class="row mt-2 mb-2"> +            <div class="col"> +                <div class="btn-group btn-group-sm" role="group" +                     aria-label="{% trans 'Export' %}"> +                    <a class="btn btn-success" +                       onclick="long_wait();return true;" +                       href="{% url 'generate-stats-operation' item.pk %}"> + +                        {% trans "Regenerate statistics" %} +                    </a> +                </div> +                {% with item.last_stats_update as last_stats_update%} +                {% if last_stats_update %}<small class="ml-2"> +                <em>{% trans "Last update:" %} {{last_stats_update}}</em> +            </small>{% endif %}{% endwith %} +            </div> +        </div>          <h4>{% trans "Administrative acts" %}</h4>          <div class='row'> diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 77791058a..72e06641d 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -212,4 +212,8 @@ urlpatterns = [                        'change_own_archaeologicalsite'])(              views.QAArchaeologicalSiteForm.as_view()),          name='site-qa-bulk-update-confirm', kwargs={"confirm": True}), + +    url(r'generate-stats-operation/(?P<pk>.+)/', +        views.GenerateStatsOperation.as_view(), +        name='generate-stats-operation'),  ] diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index ecacdb560..897302828 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -25,6 +25,7 @@ from django.core.urlresolvers import reverse  from django.db.models import Q  from django.http import HttpResponse, HttpResponseRedirect, Http404  from django.shortcuts import render, redirect +from django.views.generic import RedirectView  from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy  from archaeological_operations import models @@ -36,7 +37,8 @@ from ishtar_common.models import get_current_profile, IshtarSiteProfile, \      DocumentTemplate  from ishtar_common.utils import put_session_message, check_rights_condition  from ishtar_common.views import gen_generate_doc, QAItemEditForm, \ -    QABaseLockView, wizard_is_available, QAItemForm +    QABaseLockView, wizard_is_available, QAItemForm, IshtarMixin, \ +    LoginRequiredMixin  from ishtar_common.views_item import get_item, show_item, revert_item, \      new_qa_item  from ishtar_common.wizards import SearchWizard @@ -644,3 +646,36 @@ class QAArchaeologicalSiteDuplicateFormView(QAItemForm):  class QAArchaeologicalSiteForm(QAItemEditForm):      model = models.ArchaeologicalSite      form_class = forms.QAArchaeologicalSiteFormMulti + + +class GenerateStatsOperation(IshtarMixin, LoginRequiredMixin, RedirectView): +    model = models.Operation + +    def get_redirect_url(self, *args, **kwargs): +        return reverse('display-item', +                       args=[self.model.SLUG, self.item.pk]) + "#statistics" + +    def get(self, request, *args, **kwargs): +        self.item = self.model.objects.get(pk=kwargs['pk']) +        self.item._get_or_set_stats('_nb_acts', update=True) +        self.item._get_or_set_stats('_nb_indexed_acts', update=True) +        self.item._get_or_set_stats('_nb_context_records', update=True) +        self.item._get_or_set_stats('_nb_context_records_by_type', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_nb_context_records_by_periods', +                                    update=True, expected_type=list) +        self.item._get_or_set_stats('_nb_finds', update=True) +        self.item._get_or_set_stats('_nb_finds_by_material_type', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_nb_finds_by_types', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_nb_finds_by_periods', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_nb_documents', update=True) +        self.item._get_or_set_stats('_nb_documents_by_types', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_nb_stats_finds_by_ue', update=True) + +        return super(GenerateStatsOperation, self).get(request, *args, **kwargs) + + diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index ffc491ddc..f89092dba 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -118,7 +118,8 @@ class DivisionContainer(DashboardFormItem):      @property      def number_of_finds_by_place(self, update=False): -        return self._get_or_set_stats('_number_of_finds_by_place', update) +        return self._get_or_set_stats('_number_of_finds_by_place', update, +                                      expected_type=list)      def _number_of_containers_by_place(self):          return self._number_of_items_by_place( @@ -126,7 +127,8 @@ class DivisionContainer(DashboardFormItem):      @property      def number_of_containers_by_place(self, update=False): -        return self._get_or_set_stats('_number_of_containers_by_place', update) +        return self._get_or_set_stats('_number_of_containers_by_place', update, +                                      expected_type=list)      def _get_divisions(self, current_path, remaining_division, depth=0):          if not remaining_division: diff --git a/archaeological_warehouse/templates/ishtar/sheet_container.html b/archaeological_warehouse/templates/ishtar/sheet_container.html index 336684bc8..7ca39645d 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_container.html +++ b/archaeological_warehouse/templates/ishtar/sheet_container.html @@ -154,7 +154,23 @@           role="tabpanel" aria-labelledby="{{window_id}}-stats-tab">          <h3>{% trans "Statistics" %}</h3> -        <small class="centered"><em>{% trans "These numbers are updated hourly" %}</em></small> +        <div class="row mt-2 mb-2"> +            <div class="col"> +                <div class="btn-group btn-group-sm" role="group" +                     aria-label="{% trans 'Export' %}"> +                    <a class="btn btn-success" +                       onclick="long_wait();return true;" +                       href="{% url 'generate-stats-container' item.pk %}"> + +                        {% trans "Regenerate statistics" %} +                    </a> +                </div> +                {% with item.last_stats_update as last_stats_update%} +                {% if last_stats_update %}<small class="ml-2"> +                <em>{% trans "Last update:" %} {{last_stats_update}}</em> +            </small>{% endif %}{% endwith %} +            </div> +        </div>          {% if not item.number_containers and not item.number_divisions %}          <div class="alert alert-info"> @@ -188,10 +204,8 @@          {% endif %}          {% endfor %} -        <h4>{% trans "Containers" %}</h4> -          {% if item.number_of_containers_by_place %} -        <h4>{% trans "Containers by location in the warehouse" %}</h4> +        <h4>{% trans "Containers by location" %}</h4>          {% for items in item.number_of_containers_by_place %}          {% if items %}          <table class='table table-striped datatables' diff --git a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html index e6717f230..b4786de5b 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_warehouse.html +++ b/archaeological_warehouse/templates/ishtar/sheet_warehouse.html @@ -136,7 +136,24 @@      <div class="tab-pane fade" id="{{window_id}}-stats"           role="tabpanel" aria-labelledby="{{window_id}}-stats-tab">          <h3>{% trans "Statistics" %}</h3> -        <small class="centered"><em>{% trans "These numbers are updated hourly" %}</em></small> + +        <div class="row mt-2 mb-2"> +            <div class="col"> +                <div class="btn-group btn-group-sm" role="group" +                     aria-label="{% trans 'Export' %}"> +                    <a class="btn btn-success" +                       onclick="long_wait();return true;" +                       href="{% url 'generate-stats-warehouse' item.pk %}"> + +                        {% trans "Regenerate statistics" %} +                    </a> +                </div> +                {% with item.last_stats_update as last_stats_update%} +                {% if last_stats_update %}<small class="ml-2"> +                    <em>{% trans "Last update:" %} {{last_stats_update}}</em> +                </small>{% endif %}{% endwith %} +            </div> +        </div>          {% if not item.number_containers and not item.number_divisions %}          <div class="alert alert-info"> diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py index 2f43d74a6..46d812def 100644 --- a/archaeological_warehouse/urls.py +++ b/archaeological_warehouse/urls.py @@ -128,4 +128,12 @@ urlpatterns = [      url(r'container-manual-merge-items/(?P<pks>[0-9_]+?)/$',          views.ContainerManualMergeItems.as_view(),          name='container_manual_merge_items'), + +    url(r'generate-stats-container/(?P<pk>.+)/', +        views.GenerateStatsContainer.as_view(), +        name='generate-stats-container'), + +    url(r'generate-stats-warehouse/(?P<pk>.+)/', +        views.GenerateStatsWarehouse.as_view(), +        name='generate-stats-warehouse'),  ] diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 34def58cf..de0c64d19 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -21,6 +21,7 @@ import json  from django.core.urlresolvers import reverse  from django.db.models import Q +from django.views.generic import RedirectView  from django.views.generic.edit import FormView  from django.http import HttpResponse, Http404, HttpResponseRedirect  from django.shortcuts import redirect @@ -313,3 +314,27 @@ class QAContainerForm(QAItemEditForm):          # item list is necessary to verify uniqueness rules          kwargs['items'] = self.items          return kwargs + + +class GenerateStats(IshtarMixin, LoginRequiredMixin, RedirectView): +    model = None + +    def get_redirect_url(self, *args, **kwargs): +        return reverse('display-item', +                       args=[self.model.SLUG, self.item.pk]) + "#stats" + +    def get(self, request, *args, **kwargs): +        self.item = self.model.objects.get(pk=kwargs['pk']) +        self.item._get_or_set_stats('_number_of_finds_by_place', update=True, +                                    expected_type=list) +        self.item._get_or_set_stats('_number_of_containers_by_place', +                                    update=True, expected_type=list) +        return super(GenerateStats, self).get(request, *args, **kwargs) + + +class GenerateStatsContainer(GenerateStats): +    model = models.Container + + +class GenerateStatsWarehouse(GenerateStats): +    model = models.Warehouse diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 2d3320e2e..6eea042ce 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -3403,33 +3403,34 @@ class DashboardFormItem(object):      Provide methods to manage statistics      """ -    def _get_or_set_stats(self, funcname, update, -                          timeout=settings.CACHE_TIMEOUT, +    def last_stats_update(self): +        model_name = self._meta.app_label + "." + self._meta.model_name +        q = StatsCache.objects.filter( +            model=model_name, model_pk=self.pk).order_by("-updated") +        if not q.count(): +            return +        return q.all()[0].updated + +    def _get_or_set_stats(self, funcname, update=False,                            expected_type=None): -        values = {} -        from_cache = False          model_name = self._meta.app_label + "." + self._meta.model_name          sc, __ = StatsCache.objects.get_or_create(              model=model_name, model_pk=self.pk          ) -        now = datetime.datetime.now() -        if not settings.DEBUG and ( -                not update and sc.values and funcname in sc.values and ( -                sc.updated + datetime.timedelta(seconds=timeout)) > now): +        if not update:              values = sc.values -            from_cache = True -        if funcname not in values: +            if funcname not in values: +                if expected_type is not None: +                    return expected_type() +                return 0 +        else:              values = update_stats(sc, self, funcname)          if funcname in values:              values = values[funcname]          else:              values = 0          if expected_type is not None and not isinstance(values, expected_type): -            if from_cache: -                return self._get_or_set_stats(funcname, True, -                                              expected_type=expected_type) -            else: -                return expected_type() +            return expected_type()          return values      @classmethod | 
