From 1bea1974bbc7d713f142fc84e59964e201693d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sat, 28 May 2016 14:34:32 +0200 Subject: [PATCH] general: simplify acquisition of parent content (#11110) --- README | 8 +--- combo/data/migrations/0018_parentcontentcell.py | 31 ++++++++++++++ combo/data/migrations/0019_create_parent_cells.py | 35 +++++++++++++++ combo/data/models.py | 52 +++++++++++------------ combo/manager/templates/combo/page_view.html | 11 ----- combo/manager/views.py | 45 ++++++++++++++------ combo/public/views.py | 39 ++++------------- tests/test_public.py | 3 +- 8 files changed, 137 insertions(+), 87 deletions(-) create mode 100644 combo/data/migrations/0018_parentcontentcell.py create mode 100644 combo/data/migrations/0019_create_parent_cells.py diff --git a/README b/README index f3c8ad3..7c795a8 100644 --- a/README +++ b/README @@ -57,13 +57,7 @@ associated with a placeholder ('placeholder' attribute) and its order within ('order' attribute). A placeholder can be marked as 'acquired' (see "footer" in the example above), -this makes its cells automatically inherited from a parent page; the presence -of a cell of type 'Unlock Marker' will stop this acquisition mechanism, this -makes it possible to have a different content for those placeholders in -specific pages or sections have the site. - - Note: in the case of placeholder acquisition the site index page will be - inserted as the top of the page hierarchy. +this way a cell of "same as parent" type will automatically be added. Settings diff --git a/combo/data/migrations/0018_parentcontentcell.py b/combo/data/migrations/0018_parentcontentcell.py new file mode 100644 index 0000000..41542f4 --- /dev/null +++ b/combo/data/migrations/0018_parentcontentcell.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0006_require_contenttypes_0002'), + ('data', '0017_menucell_root_page'), + ] + + operations = [ + migrations.CreateModel( + name='ParentContentCell', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('placeholder', models.CharField(max_length=20)), + ('order', models.PositiveIntegerField()), + ('slug', models.SlugField(verbose_name='Slug', blank=True)), + ('public', models.BooleanField(default=True, verbose_name='Public')), + ('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')), + ('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)), + ('page', models.ForeignKey(to='data.Page')), + ], + options={ + 'verbose_name': 'Parent Content', + }, + ), + ] diff --git a/combo/data/migrations/0019_create_parent_cells.py b/combo/data/migrations/0019_create_parent_cells.py new file mode 100644 index 0000000..c8f6f77 --- /dev/null +++ b/combo/data/migrations/0019_create_parent_cells.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models + +def create_parent_content_cells(apps, schema_editor): + Page = apps.get_model('data', 'Page') + UnlockMarkerCell = apps.get_model('data', 'UnlockMarkerCell') + ParentContentCell = apps.get_model('data', 'ParentContentCell') + for page in Page.objects.all(): + combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(page.template_name) + for placeholder_key, placeholder_value in combo_template['placeholders'].items(): + if not placeholder_value.get('acquired'): + continue + is_unlocked = UnlockMarkerCell.objects.filter(page=page, + placeholder=placeholder_key).count() + if is_unlocked: + continue + # not unlocked -> add a new ParentContentCell + cell, created = ParentContentCell.objects.get_or_create( + page=page, placeholder=placeholder_key, order=0) + if created: + cell.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('data', '0018_parentcontentcell'), + ] + + operations = [ + migrations.RunPython(create_parent_content_cells), + ] diff --git a/combo/data/models.py b/combo/data/models.py index 0051c2a..cf6547c 100644 --- a/combo/data/models.py +++ b/combo/data/models.py @@ -175,32 +175,6 @@ class Page(models.Model): fill_list(object_list) return reordered - def get_unlocked_placeholders(self, cells=None): - combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(self.template_name) - if self.slug == 'index': - # on the site index page, there are no unlocked placeholder. - return combo_template['placeholders'].keys() - - if cells is None: - cells = CellBase.get_cells(page_id=self.id) - - # on the other page sites, look for unlock markers - unlocked_placeholders = [] - for cell in cells: - if not isinstance(cell, UnlockMarkerCell): - continue - if cell.page_id == self.id: - unlocked_placeholders.append(cell.placeholder) - return unlocked_placeholders - - def get_locked_placeholders(self, cells=None): - combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(self.template_name) - lockable_placeholders = [x for x in combo_template['placeholders'] if ( - combo_template['placeholders'].get(x).get('acquired'))] - unlocked_placeholders = self.get_unlocked_placeholders(cells) - locked_placeholders = set(lockable_placeholders) - set(unlocked_placeholders) - return list(locked_placeholders) - def visibility(self): if self.public: return _('Public') @@ -485,6 +459,8 @@ class FortuneCell(CellBase): @register_cell_class class UnlockMarkerCell(CellBase): + # XXX: this is kept to smooth transitions, it should be removed once all + # sites # have been migrated to ParentContentCell """Marks an 'acquired' placeholder as unlocked.""" visible = False @@ -723,3 +699,27 @@ class ParametersCell(CellBase): def get_default_form_class(self): from .forms import ParametersCellForm return ParametersCellForm + + +@register_cell_class +class ParentContentCell(CellBase): + class Meta: + verbose_name = _('Same as parent') + + def get_cells(self): + if self.page.parent: + parent_page = self.page.parent + elif self.page.slug != 'index': + parent_page = Page.objects.get(slug='index', parent=None) + else: + return [] + cells = CellBase.get_cells(placeholder=self.placeholder, page=parent_page) + for i, cell in enumerate(cells): + if not isinstance(cell, ParentContentCell): + continue + cells[i:i+1] = cell.get_cells() + break + return cells + + def render(self, context): + return '' diff --git a/combo/manager/templates/combo/page_view.html b/combo/manager/templates/combo/page_view.html index 17a7dde..7217f58 100644 --- a/combo/manager/templates/combo/page_view.html +++ b/combo/manager/templates/combo/page_view.html @@ -63,17 +63,6 @@ -{% if extra_placeholders %} -
-

Extra blocks

- -
-{% endif %} -
diff --git a/combo/manager/views.py b/combo/manager/views.py index 90463a6..e6464fe 100644 --- a/combo/manager/views.py +++ b/combo/manager/views.py @@ -31,7 +31,7 @@ from django.views.decorators.csrf import requires_csrf_token from django.views.generic import (TemplateView, RedirectView, DetailView, CreateView, UpdateView, ListView, DeleteView, FormView) -from combo.data.models import Page, CellBase, UnlockMarkerCell +from combo.data.models import Page, CellBase, ParentContentCell from combo.data.library import get_cell_class from combo import plugins @@ -89,6 +89,16 @@ class PageAddView(CreateView): initial['title'] = _('Home') return initial + def form_valid(self, form): + response = super(PageAddView, self).form_valid(form) + if self.object.slug != 'index' or self.object.parent_id: + combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(self.object.template_name) + for placeholder_key, placeholder in combo_template['placeholders'].items(): + if placeholder.get('acquired') is True: + ParentContentCell(page=self.object, placeholder=placeholder_key, order=0).save() + + return response + def get_success_url(self): return reverse('combo-manager-page-view', kwargs={'pk': self.object.id}) @@ -106,6 +116,25 @@ class PageEditView(UpdateView): class PageSelectTemplateView(PageEditView): form_class = PageSelectTemplateForm + def form_valid(self, form): + old_template_name = self.get_object().template_name + new_template_name = self.object.template_name + response = super(PageSelectTemplateView, self).form_valid(form) + if old_template_name != new_template_name: + old_template = settings.COMBO_PUBLIC_TEMPLATES.get(old_template_name) + new_template = settings.COMBO_PUBLIC_TEMPLATES.get(new_template_name) + page_cells = CellBase.get_cells(page_id=self.object.id) + for placeholder_key, placeholder in new_template['placeholders'].items(): + if not placeholder.get('acquired') is True: + continue + if placeholder_key in old_template: + continue + if [x for x in page_cells if x.placeholder == placeholder_key]: + # skip placeholders that already have cells + continue + ParentContentCell(page=self.object, placeholder=placeholder_key, order=0).save() + return response + page_select_template = PageSelectTemplateView.as_view() @@ -161,26 +190,18 @@ class PageView(DetailView): cells = CellBase.get_cells(page_id=self.object.id) template = self.object.template_name placeholders = [] - extra_placeholders = [] combo_template = settings.COMBO_PUBLIC_TEMPLATES.get(template) - unlocked_placeholders = self.object.get_unlocked_placeholders(cells) - for placeholder_key, placeholder in combo_template['placeholders'].items(): placeholder_dict = { 'key': placeholder_key, 'name': placeholder['name'], } - if placeholder.get('acquired') and not placeholder_key in unlocked_placeholders: - extra_placeholders.append(placeholder_dict) - else: - placeholder_dict['cells'] = [x for x in cells if ( - x.placeholder == placeholder_key)] - placeholders.append(placeholder_dict) + placeholder_dict['cells'] = [x for x in cells if ( + x.placeholder == placeholder_key)] + placeholders.append(placeholder_dict) - context['unlock'] = UnlockMarkerCell.get_cell_types()[0] context['placeholders'] = placeholders - context['extra_placeholders'] = extra_placeholders return context page_view = requires_csrf_token(PageView.as_view()) diff --git a/combo/public/views.py b/combo/public/views.py index 58a7247..6bd8b40 100644 --- a/combo/public/views.py +++ b/combo/public/views.py @@ -36,7 +36,7 @@ try: except ImportError: get_idps = lambda: [] -from combo.data.models import CellBase, Page +from combo.data.models import CellBase, Page, ParentContentCell def login(request, *args, **kwargs): @@ -97,33 +97,12 @@ def ajax_page_cell(request, page_pk, cell_reference): return HttpResponse(cell.render(context), content_type='text/html') -def extend_with_locked_placeholders_cells(cells, page, pages): - locked_placeholders = page.get_locked_placeholders(cells) - - if locked_placeholders: - # there are some acquired placeholders, look in parent pages for - # appropriate content. - try: - # add the site index page as ultimate parent - if pages[0].slug != 'index': - pages.insert(0, Page.objects.get(slug='index')) - except Page.DoesNotExist: - pass - unlocker_cells = CellBase.get_cells(page_id__in=[x.id for x in pages]) - found_placeholders = {} - for parent_page in reversed(pages[:-1]): - for placeholder in parent_page.get_unlocked_placeholders(unlocker_cells): - if not placeholder in locked_placeholders: - continue - if not placeholder in found_placeholders: - found_placeholders[placeholder] = parent_page.id - if len(found_placeholders) == len(locked_placeholders): - break - - # add found cells to the page cells - for placeholder_key, page_id in found_placeholders.items(): - cells.extend([x for x in unlocker_cells if x.page_id == page_id and - x.placeholder == placeholder_key]) +def extend_with_parent_cells(cells): + for cell in cells[:]: + if not isinstance(cell, ParentContentCell): + continue + idx = cells.index(cell) + cells[idx:idx+1] = cell.get_cells() def skeleton(request): @@ -188,7 +167,7 @@ def skeleton(request): pages = selected_page.get_parents_and_self() cells = CellBase.get_cells(page_id=selected_page.id) - extend_with_locked_placeholders_cells(cells, selected_page, pages) + extend_with_parent_cells(cells) combo_template = settings.COMBO_PUBLIC_TEMPLATES[selected_page.template_name] @@ -262,7 +241,7 @@ def publish_page(request, page, status=200, template_name=None): return HttpResponseRedirect(page.redirect_url) cells = CellBase.get_cells(page_id=page.id) - extend_with_locked_placeholders_cells(cells, page, pages) + extend_with_parent_cells(cells) cells = [x for x in cells if x.is_visible(user=request.user)] cell_with_badges = CellBase.get_cells(cell_filter=lambda x: bool(x.get_badge)) diff --git a/tests/test_public.py b/tests/test_public.py index ea9b6f3..efbd873 100644 --- a/tests/test_public.py +++ b/tests/test_public.py @@ -4,7 +4,7 @@ import pytest import urllib from combo.wsgi import application -from combo.data.models import Page, CellBase, TextCell +from combo.data.models import Page, CellBase, TextCell, ParentContentCell pytestmark = pytest.mark.django_db @@ -60,6 +60,7 @@ def test_page_footer_acquisition(app): page = Page(title='Second', slug='second', template_name='standard') page.save() + ParentContentCell(page=page, placeholder='footer', order=0).save() resp = app.get('/second', status=301) assert resp.location == 'http://localhost:80/second/' resp = app.get('/second/', status=200) -- 2.8.1