Projet

Général

Profil

0001-assets-add-generic-assets-for-cells-40223.patch

Lauréline Guérin, 12 mars 2020 11:53

Télécharger (17,8 ko)

Voir les différences:

Subject: [PATCH 1/3] assets: add generic assets for cells (#40223)

 combo/apps/assets/templatetags/assets.py      | 17 ++++-
 combo/apps/assets/views.py                    |  6 +-
 combo/data/models.py                          | 63 +++++++++++++++++--
 combo/manager/views.py                        |  2 +-
 .../combo/asset_picture_fragment.html         |  7 +++
 combo/public/templates/combo/feed-cell.html   |  1 +
 combo/public/templates/combo/json-cell.html   |  1 +
 .../templates/combo/json-list-cell.html       |  1 +
 combo/public/templates/combo/link-cell.html   |  1 +
 .../templates/combo/link-list-cell.html       |  1 +
 combo/public/templates/combo/text-cell.html   |  1 +
 combo/public/views.py                         |  6 +-
 combo/settings.py                             | 28 +++++++++
 tests/test_cells.py                           | 62 ++++++++++++++++++
 tests/test_manager.py                         |  3 +-
 tests/test_public_templatetags.py             | 29 ++++++++-
 16 files changed, 218 insertions(+), 11 deletions(-)
 create mode 100644 combo/public/templates/combo/asset_picture_fragment.html
combo/apps/assets/templatetags/assets.py
62 62

  
63 63
    return get_thumbnail(asset, geometry_string, **kwargs).url
64 64

  
65

  
65 66
@register.simple_tag
66 67
def asset_css_url(*args, **kwargs):
67 68
    url = asset_url(*args, **kwargs)
......
72 73

  
73 74

  
74 75
@register.simple_tag
75
def get_asset(key):
76
def get_asset(*args, **kwargs):
77
    key = None
78
    if 'cell' in kwargs and 'type' in kwargs:
79
        try:
80
            if not kwargs['cell'].can_have_assets():
81
                return None
82
            key = kwargs['cell'].get_asset_slot_key(kwargs['type'])
83
        except AttributeError:
84
            return None
85
    elif len(args) == 1:
86
        key = args[0]
87

  
88
    if not key:
89
        return None
90

  
76 91
    try:
77 92
        return Asset.objects.get(key=key)
78 93
    except Asset.DoesNotExist:
combo/apps/assets/views.py
103 103
        assets = dict([(x.key, x) for x in Asset.objects.all()])
104 104
        uniq_slots = {}
105 105
        uniq_slots.update(settings.COMBO_ASSET_SLOTS)
106
        for cell in CellBase.get_cells(
107
                cell_filter=lambda x: bool(x.get_asset_slots)):
106
        cells = CellBase.get_cells(select_related={
107
            '__all__': ['page'],
108
            'data_linkcell': ['link_page']})
109
        for cell in cells:
108 110
            uniq_slots.update(cell.get_asset_slots())
109 111
        for key, value in uniq_slots.items():
110 112
            yield cls(key,
combo/data/models.py
577 577
    # get_badge(self, context); set to None so cell types can be skipped easily
578 578
    get_badge = None
579 579

  
580
    # get_asset_slots(self); set to None so cell types can be skipped easily
581
    get_asset_slots = None
582

  
583 580
    # message displayed when the cell is loaded asynchronously
584 581
    loading_message = _('Loading...')
585 582

  
......
623 620
    def css_class_names(self):
624 621
        return ' '.join([self.class_name, self.legacy_class_name, self.extra_css_class])
625 622

  
623
    def can_have_assets(self):
624
        return self.get_slug_for_asset() and self.get_asset_slot_templates()
625

  
626
    def get_slug_for_asset(self):
627
        return self.slug
628

  
629
    def get_label_for_asset(self):
630
        return _(u'%(cell_label)s on page %(page_name)s (%(page_slug)s)') % {
631
            'cell_label': str(self),
632
            'page_name': str(self.page),
633
            'page_slug': self.page.slug,
634
        }
635

  
636
    def get_asset_slot_key(self, key):
637
        return 'cell:%s:%s:%s' % (
638
            self.get_cell_type_str(),
639
            key,
640
            self.get_slug_for_asset())
641

  
642
    def get_asset_slot_templates(self):
643
        return settings.COMBO_CELL_ASSET_SLOTS.get(self.get_cell_type_str()) or {}
644

  
645
    def get_asset_slots(self):
646
        if not self.can_have_assets():
647
            return {}
648

  
649
        slot_templates = self.get_asset_slot_templates()
650
        slots = {}
651
        for slot_template_key, slot_template_data in slot_templates.items():
652
            suffix = ''
653
            if slot_template_data.get('suffix'):
654
                suffix = ' (%s)' % slot_template_data['suffix']
655
            slot_key = self.get_asset_slot_key(slot_template_key)
656
            label = u'%(prefix)s — %(label)s%(suffix)s' % {
657
                'prefix': slot_template_data['prefix'],
658
                'label': self.get_label_for_asset(),
659
                'suffix': suffix
660
            }
661
            slots[slot_key] = {
662
                'label': label
663
            }
664
            slots[slot_key].update(slot_template_data)
665
        return slots
666

  
626 667
    @classmethod
627 668
    def get_cell_classes(cls, class_filter=lambda x: True):
628 669
        for klass in get_cell_classes():
......
673 714
                continue
674 715
            cells_queryset = klass.objects.filter(**kwargs)
675 716
            if select_related:
676
                cells_queryset = cells_queryset.select_related(*select_related)
717
                cells_queryset = cells_queryset.select_related(
718
                    *select_related.get('__all__', []),
719
                    *select_related.get(klass.get_cell_type_str(), []))
677 720
            cells.extend(cells_queryset)
678 721
        if prefetch_validity_info:
679 722
            validity_info_list = list(ValidityInfo.objects.select_related('content_type'))
......
1059 1102
            return None
1060 1103
        return utils.ellipsize(title)
1061 1104

  
1105
    def get_slug_for_asset(self):
1106
        if self.placeholder and self.placeholder.startswith('_'):
1107
            return
1108
        if self.link_page:
1109
            return self.link_page.slug
1110
        return self.slug
1111

  
1112
    def get_label_for_asset(self):
1113
        if self.link_page:
1114
            return str(self)
1115
        return super().get_label_for_asset()
1116

  
1062 1117
    def get_url(self, context=None):
1063 1118
        context = context or {}
1064 1119
        if self.link_page:
combo/manager/views.py
95 95

  
96 96
def invalid_cell_report(request):
97 97
    invalid_cells = CellBase.get_cells(
98
        select_related=['page'],
98
        select_related={'__all__': ['page']},
99 99
        page__snapshot__isnull=True,
100 100
        validity_info__invalid_since__isnull=False)
101 101
    invalid_cells = [c for c in invalid_cells if c.placeholder and not c.placeholder.startswith('_')]
combo/public/templates/combo/asset_picture_fragment.html
1
{% load assets %}
2
{% get_asset cell=cell type='picture' as asset %}
3
{% if asset %}
4
  <picture>
5
  <img src="{% asset_url asset size="660x360" crop="center" upscale=False %}" alt="">
6
  </picture>
7
{% endif %}
combo/public/templates/combo/feed-cell.html
3 3
{% if cell.title %}
4 4
<h2>{{ cell.title }}</h2>
5 5
{% endif %}
6
{% include "combo/asset_picture_fragment.html" %}
6 7
<div class="feed-content">
7 8
{% for entry in feed.entries %}
8 9
{% if entry.link %}
combo/public/templates/combo/json-cell.html
1 1
{% block cell-content %}
2 2
{% if title %}<h2>{{title}}</h2>{% endif %}
3
{% include "combo/asset_picture_fragment.html" %}
3 4
<!--
4 5
{{json}}
5 6
-->
combo/public/templates/combo/json-list-cell.html
1 1
{% block cell-content %}
2 2
<div class="links-list">
3 3
{% if title %}<h2>{{title}}</h2>{% endif %}
4
{% include "combo/asset_picture_fragment.html" %}
4 5
{% for row in json.data %}
5 6
<ul>
6 7
<li><a href="{{row.url}}">{{row.text}}</a></li>
combo/public/templates/combo/link-cell.html
1 1
{% block cell-content %}
2
{% include "combo/asset_picture_fragment.html" %}
2 3
<a href="{{url}}">{{title}}</a>
3 4
{% endblock %}
combo/public/templates/combo/link-list-cell.html
2 2
{% spaceless %}
3 3
<div class="links-list">
4 4
  {% if title %}<h2>{{title}}</h2>{% endif %}
5
  {% include "combo/asset_picture_fragment.html" %}
5 6
  <ul>
6 7
  {% for link in links %}
7 8
    <li><a href="{{ link.url }}">{{ link.title }}</a></li>
combo/public/templates/combo/text-cell.html
1 1
{% block cell-content %}
2
{% include "combo/asset_picture_fragment.html" %}
2 3
{{text}}
3 4
{% endblock %}
combo/public/views.py
499 499

  
500 500
    return publish_page(request, page)
501 501

  
502

  
502 503
def publish_page(request, page, status=200, template_name=None):
503 504
    pages = page.get_parents_and_self()
504 505

  
......
518 519
        if redirect_url:
519 520
            return HttpResponseRedirect(redirect_url)
520 521

  
521
    cells = CellBase.get_cells(page=page, prefetch_validity_info=True)
522
    cells = CellBase.get_cells(
523
        page=page,
524
        select_related={'data_linkcell': ['link_page']},
525
        prefetch_validity_info=True)
522 526
    extend_with_parent_cells(cells, hierarchy=pages)
523 527
    cells = [x for x in cells if x.is_visible(user=request.user)]
524 528
    mark_duplicated_slugs(cells)
combo/settings.py
324 324

  
325 325
WCS_FORM_ASSET_SLOTS = {}
326 326

  
327
COMBO_CELL_ASSET_SLOTS = {
328
    'data_feedcell': {
329
        'picture': {
330
            'prefix': _('Picture'),
331
        },
332
    },
333
    'data_jsoncell': {
334
        'picture': {
335
            'prefix': _('Picture'),
336
        },
337
    },
338
    'data_linkcell': {
339
        'picture': {
340
            'prefix': _('Picture'),
341
        },
342
    },
343
    'data_linklistcell': {
344
        'picture': {
345
            'prefix': _('Picture'),
346
        },
347
    },
348
    'data_textcell': {
349
        'picture': {
350
            'prefix': _('Picture'),
351
        },
352
    },
353
}
354

  
327 355
# known services
328 356
KNOWN_SERVICES = {}
329 357

  
tests/test_cells.py
1051 1051
            assert check_validity.call_args_list == [mock.call()]
1052 1052
        else:
1053 1053
            assert hasattr(klass, 'check_validity') is False
1054

  
1055

  
1056
def test_cell_assets(settings, app, admin_user):
1057
    page = Page.objects.create(title='xxx', slug='test_cell_assets', template_name='standard')
1058
    text_cell = TextCell.objects.create(page=page, order=0, slug='foo')
1059
    list_cell = LinkListCell.objects.create(page=page, order=2, slug='bar')
1060
    item = LinkCell.objects.create(
1061
        page=page,
1062
        placeholder=list_cell.link_placeholder,
1063
        title='Example Site',
1064
        link_page=page,
1065
        order=1,
1066
    )
1067

  
1068
    app = login(app)
1069
    settings.COMBO_CELL_ASSET_SLOTS = {}
1070
    resp = app.get('/manage/assets/')
1071
    assert 'have any asset yet.' in resp.text
1072

  
1073
    # only text cells are defined for assets
1074
    settings.COMBO_CELL_ASSET_SLOTS = {'data_textcell': {'picture': {'prefix': 'Picture'}}}
1075
    resp = app.get('/manage/assets/')
1076
    assert u'Picture — %s' % text_cell.get_label_for_asset() in resp.text
1077
    assert u'Picture — %s' % list_cell.get_label_for_asset() not in resp.text
1078
    assert u'Picture — %s' % item.get_label_for_asset() not in resp.text
1079

  
1080
    # text and list link cells are defined for assets
1081
    settings.COMBO_CELL_ASSET_SLOTS = {
1082
        'data_textcell': {'picture': {'prefix': 'Picture'}},
1083
        'data_linklistcell': {'picture': {'prefix': 'Picture'}},
1084
        'data_linkcell': {'picture': {'prefix': 'Picture', 'suffix': 'test'}},
1085
    }
1086
    resp = app.get('/manage/assets/')
1087
    assert u'Picture — %s' % text_cell.get_label_for_asset() in resp.text
1088
    assert u'Picture — %s' % list_cell.get_label_for_asset() in resp.text
1089
    # but items are excluded
1090
    assert item.get_slug_for_asset() is None  # slug for asset is always None for items
1091
    assert u'Picture — %s' % item.get_label_for_asset() not in resp.text
1092

  
1093
    # test slugs
1094
    link_cell = LinkCell.objects.create(
1095
        page=page,
1096
        url='http://example.net/',
1097
        order=1,
1098
    )
1099
    resp = app.get('/manage/assets/')
1100
    assert link_cell.get_slug_for_asset() == ''
1101
    assert u'Picture — %s' % link_cell.get_label_for_asset() not in resp.text
1102

  
1103
    link_cell.slug = 'foo'
1104
    link_cell.save()
1105
    resp = app.get('/manage/assets/')
1106
    assert link_cell.get_slug_for_asset() == 'foo'
1107
    assert u'Picture — %s (test)' % link_cell.get_label_for_asset() in resp.text
1108

  
1109
    link_cell.slug = ''
1110
    link_cell.url = ''
1111
    link_cell.link_page = page
1112
    link_cell.save()
1113
    resp = app.get('/manage/assets/')
1114
    assert link_cell.get_slug_for_asset() == 'test_cell_assets'
1115
    assert u'Picture — %s (test)' % link_cell.get_label_for_asset() in resp.text
tests/test_manager.py
352 352
    assert '<li class="nav-right"' not in resp.text
353 353

  
354 354

  
355
def test_edit_page_num_queries(app, admin_user):
355
def test_edit_page_num_queries(settings, app, admin_user):
356
    settings.COMBO_CELL_ASSET_SLOTS = {}
356 357
    page = Page.objects.create(title='One', slug='one', parent=None, template_name='standard')
357 358
    page2 = Page.objects.create(title='Two', slug='two', parent=page, template_name='standard')
358 359
    MenuCell.objects.create(page=page, order=0)
tests/test_public_templatetags.py
13 13
from django.contrib.auth.models import User, Group, AnonymousUser
14 14
from django.utils.six import StringIO
15 15

  
16
from combo.data.models import Page
16
from combo.data.models import Page, TextCell
17 17
from combo.apps.assets.models import Asset
18 18

  
19 19
pytestmark = pytest.mark.django_db
......
141 141
                 '{% for c in country_list|get_group:"USA" %}{{c.name}},{% endfor %}')
142 142
    assert t.render(context) == 'New York,Chicago,'
143 143

  
144

  
144 145
def test_asset_template_tags():
145 146
    for path in ('uploads', 'assets'):
146 147
        if os.path.exists(default_storage.path(path)):
......
194 195
        t = Template('''{% load assets %}{% asset_url page.picture "collectivity:banner" size="200x200" %}''')
195 196
        assert t.render(Context({'page': page})) == '/media/page-pictures/test2.svg'
196 197

  
198
    cell = TextCell()
199
    with override_settings(COMBO_CELL_ASSET_SLOTS={'data_textcell': {'picture': {'prefix': 'Picture'}}}):
200
        # no slug
201
        t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
202
        assert t.render(Context({'cell': cell})) == ''
203

  
204
        # no asset
205
        cell.slug = 'foobar'
206
        t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
207
        assert t.render(Context({'cell': cell})) == ''
208

  
209
        # ok
210
        Asset.objects.create(key=cell.get_asset_slot_key('picture'), asset=File(StringIO('test'), 'test.png'))
211
        t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
212
        assert t.render(Context({'cell': cell})) == 'BANNER'
213

  
214
        # no context: AttributeError
215
        t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
216
        assert t.render(Context()) == ''
217

  
218
    with override_settings(COMBO_CELL_ASSET_SLOTS={}):
219
        # cell type not defined in COMBO_CELL_ASSET_SLOTS
220
        t = Template('''{% load assets %}{% get_asset cell=cell type='picture' as banner %}{% if banner %}BANNER{% endif %}''')
221
        assert t.render(Context({'cell': cell})) == ''
222

  
223

  
197 224
def test_startswith():
198 225
    t = Template('{% if foo|startswith:"bar" %}ok{% endif %}')
199 226
    context = Context({'foo': None})
200
-