From a30eeb11d4b654c2097065278e30fe6ee3b8c864 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 18 Feb 2020 13:55:18 +0100
Subject: [PATCH 5/6] cells: invalid cell report (#38009)

---
 combo/data/models.py                          |  8 ++++--
 .../templates/combo/invalid_cell_report.html  | 28 +++++++++++++++++++
 .../manager/templates/combo/manager_home.html |  1 +
 combo/manager/urls.py                         |  1 +
 combo/manager/views.py                        | 12 ++++++++
 tests/test_manager.py                         | 23 +++++++++++++++
 6 files changed, 71 insertions(+), 2 deletions(-)
 create mode 100644 combo/manager/templates/combo/invalid_cell_report.html

diff --git a/combo/data/models.py b/combo/data/models.py
index 5f7d756..cf5c208 100644
--- a/combo/data/models.py
+++ b/combo/data/models.py
@@ -628,10 +628,11 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
         return cell_types
 
     @classmethod
-    def get_cells(cls, cell_filter=None, skip_cell_cache=False, **kwargs):
+    def get_cells(cls, cell_filter=None, skip_cell_cache=False, select_related=None, **kwargs):
         """Returns the list of cells of various classes matching **kwargs"""
         cells = []
         pages = []
+        select_related = select_related or {}
         if 'page' in kwargs:
             pages = [kwargs['page']]
         elif 'page__in' in kwargs:
@@ -656,7 +657,10 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
                 continue
             if cell_filter and not cell_filter(klass):
                 continue
-            cells.extend(klass.objects.filter(**kwargs))
+            cells_queryset = klass.objects.filter(**kwargs)
+            if select_related:
+                cells_queryset = cells_queryset.select_related(*select_related)
+            cells.extend(cells_queryset)
         cells.sort(key=lambda x: x.order)
         return cells
 
diff --git a/combo/manager/templates/combo/invalid_cell_report.html b/combo/manager/templates/combo/invalid_cell_report.html
new file mode 100644
index 0000000..7a0ff07
--- /dev/null
+++ b/combo/manager/templates/combo/invalid_cell_report.html
@@ -0,0 +1,28 @@
+{% extends "combo/manager_base.html" %}
+{% load i18n %}
+
+{% block appbar %}
+<h2>{% trans 'Invalid cells' %}</h2>
+{% endblock %}
+
+{% block breadcrumb %}
+  {{ block.super }}
+  <a href="{% url 'combo-manager-invalid-cell-report' %}">{% trans 'Anomaly report' %}</a>
+{% endblock %}
+
+{% block content %}
+{% if object_list %}
+<ul class="objects-list">
+  {% for cell in object_list %}
+  <li>
+      {% trans "Page:" %} <a href="{% url 'combo-manager-page-view' pk=cell.page_id %}">{{ cell.page.title }}</a> -
+      {% trans "Cell:" %} <a href="{% url 'combo-manager-page-view' pk=cell.page_id %}#cell-{{ cell.get_reference }}">{{ cell.get_label }}</a>
+  </li>
+  {% endfor %}
+</ul>
+{% else %}
+<div class="big-msg-info">
+  {% trans "No invalid cell found." %}
+</div>
+{% endif %}
+{% endblock %}
diff --git a/combo/manager/templates/combo/manager_home.html b/combo/manager/templates/combo/manager_home.html
index d158b26..bcdffd8 100644
--- a/combo/manager/templates/combo/manager_home.html
+++ b/combo/manager/templates/combo/manager_home.html
@@ -9,6 +9,7 @@
 <ul class="extra-actions-menu">
  <li><a download href="{% url 'combo-manager-site-export' %}">{% trans 'Export Site' %}</a></li>
  <li><a href="{% url 'combo-manager-site-import' %}">{% trans 'Import Site' %}</a></li>
+ <li><a href="{% url 'combo-manager-invalid-cell-report' %}">{% trans 'Anomaly report' %}</a></li>
  {% for extra_action in extra_actions %}
  <li><a href="{{ extra_action.href }}">{{ extra_action.text }}</a></li>
  {% endfor %}
diff --git a/combo/manager/urls.py b/combo/manager/urls.py
index 0ec7fe2..9170658 100644
--- a/combo/manager/urls.py
+++ b/combo/manager/urls.py
@@ -28,6 +28,7 @@ urlpatterns = [
         url(r'^menu.json$', views.menu_json),
         url(r'^site-export$', views.site_export, name='combo-manager-site-export'),
         url(r'^site-import$', views.site_import, name='combo-manager-site-import'),
+        url(r'^cells/invalid-report/$', views.invalid_cell_report, name='combo-manager-invalid-cell-report'),
         url(r'^pages/add/$', views.page_add, name='combo-manager-page-add'),
         url(r'^pages/(?P<pk>\d+)/$', views.page_view,
             name='combo-manager-page-view'),
diff --git a/combo/manager/views.py b/combo/manager/views.py
index 6868a33..11c7f78 100644
--- a/combo/manager/views.py
+++ b/combo/manager/views.py
@@ -24,6 +24,7 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.http import HttpResponse, HttpResponseRedirect, Http404
 from django.shortcuts import redirect
+from django.shortcuts import render
 from django.shortcuts import get_object_or_404
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import force_text, force_bytes
@@ -91,6 +92,17 @@ class SiteImportView(FormView):
 site_import = SiteImportView.as_view()
 
 
+def invalid_cell_report(request):
+    invalid_cells = CellBase.get_cells(
+        select_related=['page'],
+        page__snapshot__isnull=True,
+        invalid_since__isnull=False)
+    context = {
+        'object_list': invalid_cells,
+    }
+    return render(request, 'combo/invalid_cell_report.html', context)
+
+
 class PageAddView(CreateView):
     model = Page
     template_name = 'combo/page_add.html'
diff --git a/tests/test_manager.py b/tests/test_manager.py
index c3d55ca..c74699f 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -580,6 +580,29 @@ def test_site_export_import_missing_group(app, admin_user):
     assert 'Missing groups: foobar' in resp.text
 
 
+def test_invalid_cell_report(app, admin_user):
+    app = login(app)
+    resp = app.get('/manage/cells/invalid-report/')
+    assert resp.context['object_list'] == []
+
+    page = Page.objects.create(title='One', slug='one', template_name='standard')
+    cell = TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=0)
+    resp = app.get('/manage/cells/invalid-report/')
+    assert resp.context['object_list'] == []
+
+    cell.mark_as_invalid('foo_bar_reason')
+    resp = app.get('/manage/cells/invalid-report/')
+    assert resp.context['object_list'] == [cell]
+    assert '<a href="/manage/pages/{}/">{}</a>'.format(page.pk, page.title) in resp.text
+    assert '<a href="/manage/pages/{}/#cell-{}">{}</a>'.format(page.pk, cell.get_reference(), cell.get_label()) in resp.text
+
+    snapshot = PageSnapshot.objects.create(page=page)
+    page.snapshot = snapshot
+    page.save()
+    resp = app.get('/manage/cells/invalid-report/')
+    assert resp.context['object_list'] == []
+
+
 def test_duplicate_page(app, admin_user):
     page = Page.objects.create(title='One', slug='one', template_name='standard', exclude_from_navigation=False)
     TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=0)
-- 
2.20.1

