cells: if a cell is invalid, display it (#38009)
This commit is contained in:
parent
39234986fe
commit
6fa8bf883a
|
@ -564,6 +564,7 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
|||
last_update_timestamp = models.DateTimeField(auto_now=True)
|
||||
|
||||
validity_info = GenericRelation(ValidityInfo)
|
||||
invalid_reason_codes = {}
|
||||
|
||||
default_form_class = None
|
||||
manager_form_factory_kwargs = {}
|
||||
|
@ -641,7 +642,7 @@ 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, prefetch_validity_info=False, **kwargs):
|
||||
"""Returns the list of cells of various classes matching **kwargs"""
|
||||
cells = []
|
||||
pages = []
|
||||
|
@ -670,6 +671,12 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
|||
if cell_filter and not cell_filter(klass):
|
||||
continue
|
||||
cells.extend(klass.objects.filter(**kwargs))
|
||||
if prefetch_validity_info:
|
||||
validity_info_list = list(ValidityInfo.objects.select_related('content_type'))
|
||||
for cell in cells:
|
||||
cell.prefetched_validity_info = [
|
||||
v for v in validity_info_list
|
||||
if v.object_id == cell.pk and v.content_type.model_class() == cell.__class__]
|
||||
cells.sort(key=lambda x: x.order)
|
||||
return cells
|
||||
|
||||
|
@ -737,8 +744,51 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
|||
def get_extra_manager_context(self):
|
||||
return {}
|
||||
|
||||
def is_visible(self, user=None):
|
||||
def mark_as_invalid(self, reason_code, force=True, save=True):
|
||||
validity_info = self.validity_info.all().first()
|
||||
if validity_info is None:
|
||||
validity_info = ValidityInfo(content_object=self)
|
||||
|
||||
if not force and validity_info.invalid_since is not None:
|
||||
# don't overwrite invalid reason already set
|
||||
return
|
||||
|
||||
if validity_info.invalid_reason_code == reason_code:
|
||||
# don't overwrite invalid_since if same reason already set
|
||||
return
|
||||
|
||||
validity_info.invalid_reason_code = reason_code
|
||||
validity_info.invalid_since = now()
|
||||
if save:
|
||||
validity_info.save()
|
||||
return validity_info
|
||||
|
||||
def mark_as_valid(self, save=True):
|
||||
validity_info = self.validity_info.all().first()
|
||||
if validity_info is None:
|
||||
return
|
||||
if save:
|
||||
validity_info.delete()
|
||||
return validity_info
|
||||
|
||||
def get_validity_info(self):
|
||||
if hasattr(self, 'prefetched_validity_info'):
|
||||
if not self.prefetched_validity_info:
|
||||
return
|
||||
return self.prefetched_validity_info[0]
|
||||
return self.validity_info.all().first()
|
||||
|
||||
def get_invalid_reason(self):
|
||||
validity_info = self.get_validity_info()
|
||||
if validity_info is None:
|
||||
return
|
||||
if not validity_info.invalid_since:
|
||||
return
|
||||
return self.invalid_reason_codes.get(
|
||||
validity_info.invalid_reason_code, validity_info.invalid_reason_code)
|
||||
|
||||
def is_visible(self, user=None):
|
||||
validity_info = self.get_validity_info()
|
||||
if validity_info is not None and validity_info.invalid_since and validity_info.invalid_since < now() - datetime.timedelta(days=2):
|
||||
return False
|
||||
return element_is_visible(self, user=user)
|
||||
|
|
|
@ -80,6 +80,7 @@ div.cell h3 span.extra-css-class {
|
|||
}
|
||||
|
||||
div.cell h3 span.additional-label,
|
||||
div.cell h3 span.invalid,
|
||||
div.cell h3 span.visibility-summary,
|
||||
div.page span.visibility-summary {
|
||||
font-size: 80%;
|
||||
|
@ -111,6 +112,16 @@ div.cell h3 span.visibility-summary {
|
|||
max-width: 30%;
|
||||
}
|
||||
|
||||
div.cell h3 span.invalid {
|
||||
color: #df2240;
|
||||
}
|
||||
|
||||
.invalid::before {
|
||||
font-family: FontAwesome;
|
||||
content: "\f071"; /* exclamation-triangle */
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
div.cell-list div h3:after {
|
||||
font-family: FontAwesome;
|
||||
content: "\f107"; /* angle-down */
|
||||
|
|
|
@ -212,6 +212,14 @@ $(function() {
|
|||
$.getJSON($form.data('label-url'),
|
||||
function(data) {
|
||||
$form.parents('div.cell').find('.additional-label i').text(data['label']);
|
||||
if (data['invalid_reason']) {
|
||||
if (! $form.parents('div.cell').find('.invalid').length) {
|
||||
$('<span class="invalid"></span>').insertAfter($form.parents('div.cell').find('.additional-label'));
|
||||
}
|
||||
$form.parents('div.cell').find('.invalid').text(data['invalid_reason']);
|
||||
} else {
|
||||
$form.parents('div.cell').find('.invalid').remove();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -146,11 +146,15 @@
|
|||
<span class="group1">
|
||||
{{ cell.get_label }}
|
||||
{% if cell.slug %} [{{cell.slug}}] {% endif %}
|
||||
{% if cell.extra_css_class %}
|
||||
<span class="extra-css-class">[{{ cell.extra_css_class }}]</span>
|
||||
{% endif %}
|
||||
<span class="additional-label">
|
||||
<i>{{cell.get_additional_label|default_if_none:""}}</i></span>
|
||||
{% if cell.extra_css_class %}
|
||||
<span class="extra-css-class">[{{ cell.extra_css_class }}]</span>
|
||||
{% endif %}
|
||||
<span class="additional-label"><i>{{cell.get_additional_label|default_if_none:""}}</i></span>
|
||||
{% with cell.get_invalid_reason as invalid_reason %}
|
||||
{% if invalid_reason %}
|
||||
<span class="invalid">{{ invalid_reason }}</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% if not cell.public %}
|
||||
<span class="visibility-summary
|
||||
|
|
|
@ -261,7 +261,7 @@ class PageView(DetailView):
|
|||
context['cell_type_groups'] = list(cell_type_groups.items())
|
||||
context['cell_type_groups'].sort(key=lambda x: x[0])
|
||||
|
||||
cells = CellBase.get_cells(page=self.object)
|
||||
cells = CellBase.get_cells(page=self.object, prefetch_validity_info=True)
|
||||
self.object.prefetched_cells = cells
|
||||
template = self.object.template_name
|
||||
placeholders = []
|
||||
|
@ -568,7 +568,10 @@ def page_order(request):
|
|||
def page_get_additional_label(request, page_pk, cell_reference):
|
||||
cell = CellBase.get_cell(cell_reference, page_id=page_pk)
|
||||
response = HttpResponse(content_type='application/json')
|
||||
json.dump({'label': force_text(cell.get_additional_label()) or ''}, response)
|
||||
json.dump({
|
||||
'label': force_text(cell.get_additional_label()) or '',
|
||||
'invalid_reason': force_text(cell.get_invalid_reason() or '')
|
||||
}, response)
|
||||
return response
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ from webtest import TestApp
|
|||
from webtest import Upload
|
||||
|
||||
from combo.wsgi import application
|
||||
from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot, LinkListCell, ParentContentCell, MenuCell
|
||||
from combo.data.models import (
|
||||
Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot,
|
||||
LinkListCell, ParentContentCell, MenuCell, ValidityInfo)
|
||||
from combo.apps.assets.models import Asset
|
||||
from combo.apps.family.models import FamilyInfosCell
|
||||
from combo.apps.search.models import SearchCell
|
||||
|
@ -153,6 +155,34 @@ def test_edit_page(app, admin_user):
|
|||
assert Page.objects.all()[0].exclude_from_navigation is False
|
||||
|
||||
|
||||
def test_edit_page_cell_invalid_placeholder(app, admin_user):
|
||||
page = Page.objects.create(title='One', slug='one', template_name='standard')
|
||||
cell = TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=1)
|
||||
cell.mark_as_invalid('foo_bar_reason')
|
||||
validity_info = ValidityInfo.objects.latest('pk')
|
||||
old_reason = validity_info.invalid_reason_code
|
||||
old_date = validity_info.invalid_since
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pages/%s/' % page.pk)
|
||||
assert '<span class="invalid">foo_bar_reason</span>' in resp.text
|
||||
|
||||
cell.mark_as_invalid('another_foo_bar_reason', force=False)
|
||||
validity_info.refresh_from_db()
|
||||
assert old_reason == validity_info.invalid_reason_code
|
||||
assert old_date == validity_info.invalid_since
|
||||
|
||||
cell.mark_as_invalid('another_foo_bar_reason')
|
||||
validity_info.refresh_from_db()
|
||||
assert validity_info.invalid_reason_code == 'another_foo_bar_reason'
|
||||
assert old_date < validity_info.invalid_since
|
||||
|
||||
cell.mark_as_valid()
|
||||
assert ValidityInfo.objects.exists() is False
|
||||
resp = app.get('/manage/pages/%s/' % page.pk)
|
||||
assert '<span class="invalid">foo_bar_reason</span>' not in resp.text
|
||||
|
||||
|
||||
def test_edit_page_optional_placeholder(app, admin_user):
|
||||
Page.objects.all().delete()
|
||||
page = Page.objects.create(title='One', slug='one', template_name='standard')
|
||||
|
|
Loading…
Reference in New Issue