diff --git a/combo/data/apps.py b/combo/data/apps.py index 61a49207..10e3f481 100644 --- a/combo/data/apps.py +++ b/combo/data/apps.py @@ -26,6 +26,9 @@ class DataConfig(AppConfig): from combo.data.models import CellBase cell_classes = [c for c in self.get_models() if c in get_cell_classes()] - for cell in CellBase.get_cells(cell_filter=lambda x: x in cell_classes, page__snapshot__isnull=True): + + for cell in CellBase.get_cells( + cell_filter=lambda x: x in cell_classes, page__snapshot__isnull=True, get_all_objects=True + ): if hasattr(cell, 'check_validity'): cell.check_validity() diff --git a/combo/data/models.py b/combo/data/models.py index 81a97f9a..85cb4959 100644 --- a/combo/data/models.py +++ b/combo/data/models.py @@ -1040,6 +1040,7 @@ class CellBase(models.Model, metaclass=CellMeta): select_related=None, load_contenttypes=False, cells_exclude=None, + get_all_objects=False, **kwargs, ): """Returns the list of cells of various classes matching **kwargs""" @@ -1074,7 +1075,10 @@ class CellBase(models.Model, metaclass=CellMeta): continue if cell_filter and not cell_filter(klass): continue - cells_queryset = klass.objects.filter(**kwargs) + manager = klass.objects + if get_all_objects and hasattr(klass, 'all_objects'): + manager = klass.all_objects + cells_queryset = manager.filter(**kwargs) if cells_exclude: cells_queryset = cells_queryset.exclude(cells_exclude) if extra_filter: @@ -2360,10 +2364,15 @@ class ConfigJsonCellManager(models.Manager): @register_cell_class class ConfigJsonCell(JsonCellBase): objects = ConfigJsonCellManager() + all_objects = models.Manager() key = models.CharField(max_length=50) parameters = JSONField(blank=True, default=dict) + invalid_reason_codes = { + 'settings_not_found': _('Cell not found in settings'), + } + def __str__(self): return force_str(_('%s (JSON Cell)') % self.get_label()) @@ -2383,6 +2392,8 @@ class ConfigJsonCell(JsonCellBase): return l def get_label(self): + if self.key not in settings.JSON_CELL_TYPES: + return _('Unknown ConfigJsonCell %s') % self.key return settings.JSON_CELL_TYPES[self.key]['name'] def set_variant(self, variant): @@ -2465,6 +2476,18 @@ class ConfigJsonCell(JsonCellBase): self.template_string = self.parameters['template_string'] return super().render(context) + def check_validity(self): + if self.key not in settings.JSON_CELL_TYPES: + self.mark_as_invalid('settings_not_found') + return + validity_info = self.get_validity_info() + if validity_info is None: + return + if validity_info.invalid_reason_code != 'settings_not_found': + # don't overwrite other invalid reasons + return + self.mark_as_valid() + @receiver(pre_save, sender=Page) def create_redirects(sender, instance, raw, **kwargs): diff --git a/combo/manager/views.py b/combo/manager/views.py index 14003071..5d8eb47a 100644 --- a/combo/manager/views.py +++ b/combo/manager/views.py @@ -185,7 +185,10 @@ site_import = SiteImportView.as_view() def invalid_cell_report(request): invalid_cells = CellBase.get_cells( - page__snapshot__isnull=True, validity_info__invalid_since__isnull=False, load_contenttypes=True + page__snapshot__isnull=True, + validity_info__invalid_since__isnull=False, + load_contenttypes=True, + get_all_objects=True, ) # manual prefetch of cell pages (for ordering and placeholders) all_pages_by_pk = {p.pk: p for p in Page.objects.filter(snapshot__isnull=True)} diff --git a/tests/test_cells.py b/tests/test_cells.py index 55f29db3..e92a5a7b 100644 --- a/tests/test_cells.py +++ b/tests/test_cells.py @@ -1258,6 +1258,44 @@ def test_config_json_cell_validity(settings, context): assert ValidityInfo.objects.exists() is False +def test_config_json_cell_check_validity(settings): + settings.JSON_CELL_TYPES = { + 'test-config-json-cell': { + 'name': 'Foobar', + }, + } + page = Page.objects.create(title='example page', slug='example-page') + cell = ConfigJsonCell.objects.create( + page=page, + placeholder='content', + order=1, + key='test-config-json-cell', + ) + cell.check_validity() + assert ValidityInfo.objects.exists() is False + + settings.JSON_CELL_TYPES = {} + cell.check_validity() + validity_info = ValidityInfo.objects.latest('pk') + assert validity_info.invalid_reason_code == 'settings_not_found' + assert validity_info.invalid_since is not None + + settings.JSON_CELL_TYPES = { + 'test-config-json-cell': { + 'name': 'Foobar', + }, + } + validity_info.invalid_reason_code = 'foobar' + validity_info.save() + cell.check_validity() + assert ValidityInfo.objects.exists() is True + + validity_info.invalid_reason_code = 'settings_not_found' + validity_info.save() + cell.check_validity() + assert ValidityInfo.objects.exists() is False + + def test_json_force_async(): cell = JsonCell() cell.url = 'http://example.net/test-force-async' @@ -1623,7 +1661,7 @@ def test_hourly(): for klass in cell_classes: klass.objects.create(page=page, placeholder='content', order=0) for klass in cell_classes: - if klass in [LinkCell, LinkListCell]: + if klass in [LinkCell, LinkListCell, ConfigJsonCell]: with mock.patch('combo.data.models.%s.check_validity' % klass.__name__) as check_validity: appconfig.hourly() assert check_validity.call_args_list == [mock.call()] diff --git a/tests/test_manager.py b/tests/test_manager.py index c6166c8f..bc7d401e 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -1272,6 +1272,17 @@ def test_invalid_cell_report(app, admin_user): resp = app.get('/manage/cells/invalid-report/') assert resp.context['object_list'] == [cell] + # unknown config cell + cell2 = ConfigJsonCell.objects.create( + page=page, + placeholder='content', + order=1, + key='test-config-json-cell', + ) + cell2.mark_as_invalid('settings_not_found') + resp = app.get('/manage/cells/invalid-report/') + assert resp.context['object_list'] == [cell, cell2] + def test_duplicate_page(app, admin_user): page = Page.objects.create(