assets: add generic assets for cells (#40223)
This commit is contained in:
parent
00131e4868
commit
5d6d0a86fc
|
@ -62,6 +62,7 @@ def asset_url(*args, **kwargs):
|
||||||
|
|
||||||
return get_thumbnail(asset, geometry_string, **kwargs).url
|
return get_thumbnail(asset, geometry_string, **kwargs).url
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def asset_css_url(*args, **kwargs):
|
def asset_css_url(*args, **kwargs):
|
||||||
url = asset_url(*args, **kwargs)
|
url = asset_url(*args, **kwargs)
|
||||||
|
@ -72,7 +73,21 @@ def asset_css_url(*args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def get_asset(key):
|
def get_asset(*args, **kwargs):
|
||||||
|
key = None
|
||||||
|
if 'cell' in kwargs and 'type' in kwargs:
|
||||||
|
try:
|
||||||
|
if not kwargs['cell'].can_have_assets():
|
||||||
|
return None
|
||||||
|
key = kwargs['cell'].get_asset_slot_key(kwargs['type'])
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
elif len(args) == 1:
|
||||||
|
key = args[0]
|
||||||
|
|
||||||
|
if not key:
|
||||||
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return Asset.objects.get(key=key)
|
return Asset.objects.get(key=key)
|
||||||
except Asset.DoesNotExist:
|
except Asset.DoesNotExist:
|
||||||
|
|
|
@ -103,8 +103,10 @@ class SlotAsset(object):
|
||||||
assets = dict([(x.key, x) for x in Asset.objects.all()])
|
assets = dict([(x.key, x) for x in Asset.objects.all()])
|
||||||
uniq_slots = {}
|
uniq_slots = {}
|
||||||
uniq_slots.update(settings.COMBO_ASSET_SLOTS)
|
uniq_slots.update(settings.COMBO_ASSET_SLOTS)
|
||||||
for cell in CellBase.get_cells(
|
cells = CellBase.get_cells(select_related={
|
||||||
cell_filter=lambda x: bool(x.get_asset_slots)):
|
'__all__': ['page'],
|
||||||
|
'data_linkcell': ['link_page']})
|
||||||
|
for cell in cells:
|
||||||
uniq_slots.update(cell.get_asset_slots())
|
uniq_slots.update(cell.get_asset_slots())
|
||||||
for key, value in uniq_slots.items():
|
for key, value in uniq_slots.items():
|
||||||
yield cls(key,
|
yield cls(key,
|
||||||
|
|
|
@ -577,9 +577,6 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
||||||
# get_badge(self, context); set to None so cell types can be skipped easily
|
# get_badge(self, context); set to None so cell types can be skipped easily
|
||||||
get_badge = None
|
get_badge = None
|
||||||
|
|
||||||
# get_asset_slots(self); set to None so cell types can be skipped easily
|
|
||||||
get_asset_slots = None
|
|
||||||
|
|
||||||
# message displayed when the cell is loaded asynchronously
|
# message displayed when the cell is loaded asynchronously
|
||||||
loading_message = _('Loading...')
|
loading_message = _('Loading...')
|
||||||
|
|
||||||
|
@ -623,6 +620,50 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
||||||
def css_class_names(self):
|
def css_class_names(self):
|
||||||
return ' '.join([self.class_name, self.legacy_class_name, self.extra_css_class])
|
return ' '.join([self.class_name, self.legacy_class_name, self.extra_css_class])
|
||||||
|
|
||||||
|
def can_have_assets(self):
|
||||||
|
return self.get_slug_for_asset() and self.get_asset_slot_templates()
|
||||||
|
|
||||||
|
def get_slug_for_asset(self):
|
||||||
|
return self.slug
|
||||||
|
|
||||||
|
def get_label_for_asset(self):
|
||||||
|
return _(u'%(cell_label)s on page %(page_name)s (%(page_slug)s)') % {
|
||||||
|
'cell_label': str(self),
|
||||||
|
'page_name': str(self.page),
|
||||||
|
'page_slug': self.page.slug,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_asset_slot_key(self, key):
|
||||||
|
return 'cell:%s:%s:%s' % (
|
||||||
|
self.get_cell_type_str(),
|
||||||
|
key,
|
||||||
|
self.get_slug_for_asset())
|
||||||
|
|
||||||
|
def get_asset_slot_templates(self):
|
||||||
|
return settings.COMBO_CELL_ASSET_SLOTS.get(self.get_cell_type_str()) or {}
|
||||||
|
|
||||||
|
def get_asset_slots(self):
|
||||||
|
if not self.can_have_assets():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
slot_templates = self.get_asset_slot_templates()
|
||||||
|
slots = {}
|
||||||
|
for slot_template_key, slot_template_data in slot_templates.items():
|
||||||
|
suffix = ''
|
||||||
|
if slot_template_data.get('suffix'):
|
||||||
|
suffix = ' (%s)' % slot_template_data['suffix']
|
||||||
|
slot_key = self.get_asset_slot_key(slot_template_key)
|
||||||
|
label = u'%(prefix)s — %(label)s%(suffix)s' % {
|
||||||
|
'prefix': slot_template_data['prefix'],
|
||||||
|
'label': self.get_label_for_asset(),
|
||||||
|
'suffix': suffix
|
||||||
|
}
|
||||||
|
slots[slot_key] = {
|
||||||
|
'label': label
|
||||||
|
}
|
||||||
|
slots[slot_key].update(slot_template_data)
|
||||||
|
return slots
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_cell_classes(cls, class_filter=lambda x: True):
|
def get_cell_classes(cls, class_filter=lambda x: True):
|
||||||
for klass in get_cell_classes():
|
for klass in get_cell_classes():
|
||||||
|
@ -673,7 +714,9 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
||||||
continue
|
continue
|
||||||
cells_queryset = klass.objects.filter(**kwargs)
|
cells_queryset = klass.objects.filter(**kwargs)
|
||||||
if select_related:
|
if select_related:
|
||||||
cells_queryset = cells_queryset.select_related(*select_related)
|
cells_queryset = cells_queryset.select_related(
|
||||||
|
*select_related.get('__all__', []),
|
||||||
|
*select_related.get(klass.get_cell_type_str(), []))
|
||||||
cells.extend(cells_queryset)
|
cells.extend(cells_queryset)
|
||||||
if prefetch_validity_info:
|
if prefetch_validity_info:
|
||||||
validity_info_list = list(ValidityInfo.objects.select_related('content_type'))
|
validity_info_list = list(ValidityInfo.objects.select_related('content_type'))
|
||||||
|
@ -1059,6 +1102,18 @@ class LinkCell(CellBase):
|
||||||
return None
|
return None
|
||||||
return utils.ellipsize(title)
|
return utils.ellipsize(title)
|
||||||
|
|
||||||
|
def get_slug_for_asset(self):
|
||||||
|
if self.placeholder and self.placeholder.startswith('_'):
|
||||||
|
return
|
||||||
|
if self.link_page:
|
||||||
|
return self.link_page.slug
|
||||||
|
return self.slug
|
||||||
|
|
||||||
|
def get_label_for_asset(self):
|
||||||
|
if self.link_page:
|
||||||
|
return str(self)
|
||||||
|
return super().get_label_for_asset()
|
||||||
|
|
||||||
def get_url(self, context=None):
|
def get_url(self, context=None):
|
||||||
context = context or {}
|
context = context or {}
|
||||||
if self.link_page:
|
if self.link_page:
|
||||||
|
|
|
@ -95,7 +95,7 @@ site_import = SiteImportView.as_view()
|
||||||
|
|
||||||
def invalid_cell_report(request):
|
def invalid_cell_report(request):
|
||||||
invalid_cells = CellBase.get_cells(
|
invalid_cells = CellBase.get_cells(
|
||||||
select_related=['page'],
|
select_related={'__all__': ['page']},
|
||||||
page__snapshot__isnull=True,
|
page__snapshot__isnull=True,
|
||||||
validity_info__invalid_since__isnull=False)
|
validity_info__invalid_since__isnull=False)
|
||||||
invalid_cells = [c for c in invalid_cells if c.placeholder and not c.placeholder.startswith('_')]
|
invalid_cells = [c for c in invalid_cells if c.placeholder and not c.placeholder.startswith('_')]
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% load assets %}
|
||||||
|
{% get_asset cell=cell type='picture' as asset %}
|
||||||
|
{% if asset %}
|
||||||
|
<picture>
|
||||||
|
<img src="{% asset_url asset size="660x360" crop="center" upscale=False %}" alt="">
|
||||||
|
</picture>
|
||||||
|
{% endif %}
|
|
@ -3,6 +3,7 @@
|
||||||
{% if cell.title %}
|
{% if cell.title %}
|
||||||
<h2>{{ cell.title }}</h2>
|
<h2>{{ cell.title }}</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
<div class="feed-content">
|
<div class="feed-content">
|
||||||
{% for entry in feed.entries %}
|
{% for entry in feed.entries %}
|
||||||
{% if entry.link %}
|
{% if entry.link %}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{% block cell-content %}
|
{% block cell-content %}
|
||||||
{% if title %}<h2>{{title}}</h2>{% endif %}
|
{% if title %}<h2>{{title}}</h2>{% endif %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
<!--
|
<!--
|
||||||
{{json}}
|
{{json}}
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% block cell-content %}
|
{% block cell-content %}
|
||||||
<div class="links-list">
|
<div class="links-list">
|
||||||
{% if title %}<h2>{{title}}</h2>{% endif %}
|
{% if title %}<h2>{{title}}</h2>{% endif %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
{% for row in json.data %}
|
{% for row in json.data %}
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{{row.url}}">{{row.text}}</a></li>
|
<li><a href="{{row.url}}">{{row.text}}</a></li>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
{% block cell-content %}
|
{% block cell-content %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
<a href="{{url}}">{{title}}</a>
|
<a href="{{url}}">{{title}}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{% spaceless %}
|
{% spaceless %}
|
||||||
<div class="links-list">
|
<div class="links-list">
|
||||||
{% if title %}<h2>{{title}}</h2>{% endif %}
|
{% if title %}<h2>{{title}}</h2>{% endif %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
<ul>
|
<ul>
|
||||||
{% for link in links %}
|
{% for link in links %}
|
||||||
<li><a href="{{ link.url }}">{{ link.title }}</a></li>
|
<li><a href="{{ link.url }}">{{ link.title }}</a></li>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
{% block cell-content %}
|
{% block cell-content %}
|
||||||
|
{% include "combo/asset_picture_fragment.html" %}
|
||||||
{{text}}
|
{{text}}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -499,6 +499,7 @@ def page(request):
|
||||||
|
|
||||||
return publish_page(request, page)
|
return publish_page(request, page)
|
||||||
|
|
||||||
|
|
||||||
def publish_page(request, page, status=200, template_name=None):
|
def publish_page(request, page, status=200, template_name=None):
|
||||||
pages = page.get_parents_and_self()
|
pages = page.get_parents_and_self()
|
||||||
|
|
||||||
|
@ -518,7 +519,10 @@ def publish_page(request, page, status=200, template_name=None):
|
||||||
if redirect_url:
|
if redirect_url:
|
||||||
return HttpResponseRedirect(redirect_url)
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
|
||||||
cells = CellBase.get_cells(page=page, prefetch_validity_info=True)
|
cells = CellBase.get_cells(
|
||||||
|
page=page,
|
||||||
|
select_related={'data_linkcell': ['link_page']},
|
||||||
|
prefetch_validity_info=True)
|
||||||
extend_with_parent_cells(cells, hierarchy=pages)
|
extend_with_parent_cells(cells, hierarchy=pages)
|
||||||
cells = [x for x in cells if x.is_visible(user=request.user)]
|
cells = [x for x in cells if x.is_visible(user=request.user)]
|
||||||
mark_duplicated_slugs(cells)
|
mark_duplicated_slugs(cells)
|
||||||
|
|
|
@ -324,6 +324,19 @@ WCS_CATEGORY_ASSET_SLOTS = {
|
||||||
|
|
||||||
WCS_FORM_ASSET_SLOTS = {}
|
WCS_FORM_ASSET_SLOTS = {}
|
||||||
|
|
||||||
|
COMBO_CELL_ASSET_SLOTS = {
|
||||||
|
'data_feedcell': {
|
||||||
|
'picture': {
|
||||||
|
'prefix': _('Picture'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'data_linklistcell': {
|
||||||
|
'picture': {
|
||||||
|
'prefix': _('Picture'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# known services
|
# known services
|
||||||
KNOWN_SERVICES = {}
|
KNOWN_SERVICES = {}
|
||||||
|
|
||||||
|
|
|
@ -1051,3 +1051,65 @@ def test_hourly():
|
||||||
assert check_validity.call_args_list == [mock.call()]
|
assert check_validity.call_args_list == [mock.call()]
|
||||||
else:
|
else:
|
||||||
assert hasattr(klass, 'check_validity') is False
|
assert hasattr(klass, 'check_validity') is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_cell_assets(settings, app, admin_user):
|
||||||
|
page = Page.objects.create(title='xxx', slug='test_cell_assets', template_name='standard')
|
||||||
|
text_cell = TextCell.objects.create(page=page, order=0, slug='foo')
|
||||||
|
list_cell = LinkListCell.objects.create(page=page, order=2, slug='bar')
|
||||||
|
item = LinkCell.objects.create(
|
||||||
|
page=page,
|
||||||
|
placeholder=list_cell.link_placeholder,
|
||||||
|
title='Example Site',
|
||||||
|
link_page=page,
|
||||||
|
order=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
app = login(app)
|
||||||
|
settings.COMBO_CELL_ASSET_SLOTS = {}
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert 'have any asset yet.' in resp.text
|
||||||
|
|
||||||
|
# only text cells are defined for assets
|
||||||
|
settings.COMBO_CELL_ASSET_SLOTS = {'data_textcell': {'picture': {'prefix': 'Picture'}}}
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert u'Picture — %s' % text_cell.get_label_for_asset() in resp.text
|
||||||
|
assert u'Picture — %s' % list_cell.get_label_for_asset() not in resp.text
|
||||||
|
assert u'Picture — %s' % item.get_label_for_asset() not in resp.text
|
||||||
|
|
||||||
|
# text and list link cells are defined for assets
|
||||||
|
settings.COMBO_CELL_ASSET_SLOTS = {
|
||||||
|
'data_textcell': {'picture': {'prefix': 'Picture'}},
|
||||||
|
'data_linklistcell': {'picture': {'prefix': 'Picture'}},
|
||||||
|
'data_linkcell': {'picture': {'prefix': 'Picture', 'suffix': 'test'}},
|
||||||
|
}
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert u'Picture — %s' % text_cell.get_label_for_asset() in resp.text
|
||||||
|
assert u'Picture — %s' % list_cell.get_label_for_asset() in resp.text
|
||||||
|
# but items are excluded
|
||||||
|
assert item.get_slug_for_asset() is None # slug for asset is always None for items
|
||||||
|
assert u'Picture — %s' % item.get_label_for_asset() not in resp.text
|
||||||
|
|
||||||
|
# test slugs
|
||||||
|
link_cell = LinkCell.objects.create(
|
||||||
|
page=page,
|
||||||
|
url='http://example.net/',
|
||||||
|
order=1,
|
||||||
|
)
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert link_cell.get_slug_for_asset() == ''
|
||||||
|
assert u'Picture — %s' % link_cell.get_label_for_asset() not in resp.text
|
||||||
|
|
||||||
|
link_cell.slug = 'foo'
|
||||||
|
link_cell.save()
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert link_cell.get_slug_for_asset() == 'foo'
|
||||||
|
assert u'Picture — %s (test)' % link_cell.get_label_for_asset() in resp.text
|
||||||
|
|
||||||
|
link_cell.slug = ''
|
||||||
|
link_cell.url = ''
|
||||||
|
link_cell.link_page = page
|
||||||
|
link_cell.save()
|
||||||
|
resp = app.get('/manage/assets/')
|
||||||
|
assert link_cell.get_slug_for_asset() == 'test_cell_assets'
|
||||||
|
assert u'Picture — %s (test)' % link_cell.get_label_for_asset() in resp.text
|
||||||
|
|
|
@ -352,7 +352,8 @@ def test_edit_page_navigation(app, admin_user):
|
||||||
assert '<li class="nav-right"' not in resp.text
|
assert '<li class="nav-right"' not in resp.text
|
||||||
|
|
||||||
|
|
||||||
def test_edit_page_num_queries(app, admin_user):
|
def test_edit_page_num_queries(settings, app, admin_user):
|
||||||
|
settings.COMBO_CELL_ASSET_SLOTS = {}
|
||||||
page = Page.objects.create(title='One', slug='one', parent=None, template_name='standard')
|
page = Page.objects.create(title='One', slug='one', parent=None, template_name='standard')
|
||||||
page2 = Page.objects.create(title='Two', slug='two', parent=page, template_name='standard')
|
page2 = Page.objects.create(title='Two', slug='two', parent=page, template_name='standard')
|
||||||
MenuCell.objects.create(page=page, order=0)
|
MenuCell.objects.create(page=page, order=0)
|
||||||
|
|
|
@ -13,7 +13,7 @@ from django.test.client import RequestFactory
|
||||||
from django.contrib.auth.models import User, Group, AnonymousUser
|
from django.contrib.auth.models import User, Group, AnonymousUser
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
from combo.data.models import Page
|
from combo.data.models import Page, TextCell
|
||||||
from combo.apps.assets.models import Asset
|
from combo.apps.assets.models import Asset
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
@ -141,6 +141,7 @@ def test_get_group():
|
||||||
'{% for c in country_list|get_group:"USA" %}{{c.name}},{% endfor %}')
|
'{% for c in country_list|get_group:"USA" %}{{c.name}},{% endfor %}')
|
||||||
assert t.render(context) == 'New York,Chicago,'
|
assert t.render(context) == 'New York,Chicago,'
|
||||||
|
|
||||||
|
|
||||||
def test_asset_template_tags():
|
def test_asset_template_tags():
|
||||||
for path in ('uploads', 'assets'):
|
for path in ('uploads', 'assets'):
|
||||||
if os.path.exists(default_storage.path(path)):
|
if os.path.exists(default_storage.path(path)):
|
||||||
|
@ -194,6 +195,32 @@ def test_asset_template_tags():
|
||||||
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
|
t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
|
||||||
assert t.render(Context({'page': page})) == '/media/page-pictures/test2.svg'
|
assert t.render(Context({'page': page})) == '/media/page-pictures/test2.svg'
|
||||||
|
|
||||||
|
cell = TextCell()
|
||||||
|
with override_settings(COMBO_CELL_ASSET_SLOTS={'data_textcell': {'picture': {'prefix': 'Picture'}}}):
|
||||||
|
# no slug
|
||||||
|
t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
|
||||||
|
assert t.render(Context({'cell': cell})) == ''
|
||||||
|
|
||||||
|
# no asset
|
||||||
|
cell.slug = 'foobar'
|
||||||
|
t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
|
||||||
|
assert t.render(Context({'cell': cell})) == ''
|
||||||
|
|
||||||
|
# ok
|
||||||
|
Asset.objects.create(key=cell.get_asset_slot_key('picture'), asset=File(StringIO('test'), 'test.png'))
|
||||||
|
t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
|
||||||
|
assert t.render(Context({'cell': cell})) == 'BANNER'
|
||||||
|
|
||||||
|
# no context: AttributeError
|
||||||
|
t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
|
||||||
|
assert t.render(Context()) == ''
|
||||||
|
|
||||||
|
with override_settings(COMBO_CELL_ASSET_SLOTS={}):
|
||||||
|
# cell type not defined in COMBO_CELL_ASSET_SLOTS
|
||||||
|
t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
|
||||||
|
assert t.render(Context({'cell': cell})) == ''
|
||||||
|
|
||||||
|
|
||||||
def test_startswith():
|
def test_startswith():
|
||||||
t = Template('{% if foo|startswith:"bar" %}ok{% endif %}')
|
t = Template('{% if foo|startswith:"bar" %}ok{% endif %}')
|
||||||
context = Context({'foo': None})
|
context = Context({'foo': None})
|
||||||
|
|
Loading…
Reference in New Issue