general: simplify acquisition of parent content (#11110)

This commit is contained in:
Frédéric Péters 2016-05-28 14:34:32 +02:00
parent 981e22c4d2
commit 80777c430c
8 changed files with 137 additions and 87 deletions

8
README
View File

@ -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

View File

@ -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',
},
),
]

View File

@ -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),
]

View File

@ -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 ''

View File

@ -63,17 +63,6 @@
</div>
{% if extra_placeholders %}
<div id="extra-placeholders">
<h2>Extra blocks</h2>
<ul>
{% for placeholder in extra_placeholders %}
<li><a href="{% url 'combo-manager-page-add-cell' page_pk=object.id cell_type=unlock.cell_type_str variant=unlock.variant ph_key=placeholder.key %}">{{ placeholder.name }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
</div> <!-- #sidebar -->
<div id="page-content">

View File

@ -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())

View File

@ -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))

View File

@ -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)