Projet

Général

Profil

0002-cells-add-a-cell-type-list-of-links-11006.patch

Lauréline Guérin, 10 janvier 2020 15:39

Télécharger (33,5 ko)

Voir les différences:

Subject: [PATCH 2/2] cells: add a cell type "list of links" (#11006)

 combo/apps/wcs/models.py                      |   8 +-
 combo/data/forms.py                           |  13 +-
 combo/data/migrations/0039_link_list_cell.py  |  38 +++++
 combo/data/models.py                          |  63 +++++++-
 .../combo/manager/link-list-cell-form.html    |  27 ++++
 combo/manager/static/js/combo.manager.js      |  15 ++
 .../templates/combo/link_cell_form.html       |  22 +++
 combo/manager/urls.py                         |  12 ++
 combo/manager/views.py                        | 143 +++++++++++++++++-
 .../templates/combo/link-list-cell.html       |  11 ++
 tests/test_cells.py                           |  66 +++++++-
 tests/test_manager.py                         |  72 ++++++++-
 tests/test_pages.py                           |  35 ++++-
 tests/test_wcs.py                             |  92 ++++++++++-
 14 files changed, 605 insertions(+), 12 deletions(-)
 create mode 100644 combo/data/migrations/0039_link_list_cell.py
 create mode 100644 combo/data/templates/combo/manager/link-list-cell-form.html
 create mode 100644 combo/manager/templates/combo/link_cell_form.html
 create mode 100644 combo/public/templates/combo/link-list-cell.html
combo/apps/wcs/models.py
36 36

  
37 37
@register_cell_class
38 38
class WcsFormCell(CellBase):
39
    template_name = 'combo/wcs/form.html'
40

  
41 39
    formdef_reference = models.CharField(_('Form'), max_length=150)
42 40

  
43 41
    cached_title = models.CharField(_('Title'), max_length=150)
44 42
    cached_url = models.URLField(_('URL'))
45 43
    cached_json = JSONField(blank=True)
46 44

  
45
    template_name = 'combo/wcs/form.html'
46
    add_as_link_label = _('add a form link')
47
    add_link_label = _('New form link')
48
    edit_link_label = _('Edit form link')
49
    add_as_link_code = 'form-link'
50

  
47 51
    is_enabled = classmethod(is_wcs_enabled)
48 52

  
49 53
    class Meta:
combo/data/forms.py
18 18

  
19 19
from django import forms
20 20

  
21
from .models import Page, ParametersCell, MenuCell, LinkCell, ConfigJsonCell
21
from .models import Page, ParametersCell, MenuCell, LinkCell, LinkListCell, ConfigJsonCell
22 22
from jsonfield.widgets import JSONWidget
23 23

  
24 24
from combo.utils import cache_during_request
......
41 41
                break
42 42
        return self.cleaned_data
43 43

  
44

  
44 45
class ParametersCellForm(forms.ModelForm):
45 46
    class Meta:
46 47
        model = ParametersCell
......
61 62
    pages = Page.get_as_reordered_flat_hierarchy(Page.objects.all())
62 63
    return [(x.id, '%s %s' % (u'\u00a0' * x.level * 2, x.title)) for x in pages]
63 64

  
65

  
64 66
class MenuCellForm(forms.ModelForm):
65 67
    class Meta:
66 68
        model = MenuCell
......
82 84
                choices=[(None, '-----')] + get_page_choices())
83 85

  
84 86

  
87
class LinkListCellForm(forms.ModelForm):
88
    class Meta:
89
        model = LinkListCell
90
        fields = []
91

  
92
    def __init__(self, *args, **kwargs):
93
        super(LinkListCellForm, self).__init__(*args, **kwargs)
94

  
95

  
85 96
class ConfigJsonForm(forms.ModelForm):
86 97
    formdef = []
87 98

  
combo/data/migrations/0039_link_list_cell.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import migrations, models
5
import django.db.models.deletion
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('auth', '0008_alter_user_username_max_length'),
12
        ('data', '0038_increase_jsoncell_url_max_length'),
13
    ]
14

  
15
    operations = [
16
        migrations.CreateModel(
17
            name='LinkListCell',
18
            fields=[
19
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20
                ('placeholder', models.CharField(max_length=20)),
21
                ('order', models.PositiveIntegerField()),
22
                ('slug', models.SlugField(blank=True, verbose_name='Slug')),
23
                ('extra_css_class', models.CharField(blank=True, max_length=100, verbose_name='Extra classes for CSS styling')),
24
                ('public', models.BooleanField(default=True, verbose_name='Public')),
25
                ('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
26
                ('last_update_timestamp', models.DateTimeField(auto_now=True)),
27
                ('groups', models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups')),
28
            ],
29
            options={
30
                'verbose_name': 'List of links',
31
            },
32
        ),
33
        migrations.AddField(
34
            model_name='linklistcell',
35
            name='page',
36
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page'),
37
        ),
38
    ]
combo/data/models.py
451 451
        new_page.groups.set(self.groups.all())
452 452

  
453 453
        for cell in self.get_cells():
454
            if cell.placeholder and cell.placeholder.startswith('_'):
455
                continue
454 456
            cell.duplicate(page_target=new_page)
455 457

  
456 458
        return new_page
......
756 758
    def import_subobjects(self, cell_json):
757 759
        pass
758 760

  
759
    def duplicate(self, page_target=None):
761
    def duplicate(self, page_target=None, placeholder=None):
760 762
        # clone current cell
761 763
        new_cell = copy.deepcopy(self)
762 764
        new_cell.pk = None
763 765
        # set page
764 766
        new_cell.page = page_target or self.page
767
        # set placeholder
768
        new_cell.placeholder = placeholder or new_cell.placeholder
765 769
        # store new cell
766 770
        new_cell.save()
767 771

  
......
905 909
    anchor = models.CharField(_('Anchor'), max_length=150, blank=True)
906 910

  
907 911
    template_name = 'combo/link-cell.html'
912
    add_as_link_label = _('add a link')
913
    add_link_label = _('New link')
914
    edit_link_label = _('Edit link')
915
    add_as_link_code = 'link'
908 916

  
909 917
    class Meta:
910 918
        verbose_name = _('Link')
......
950 958
        return []
951 959

  
952 960

  
961
@register_cell_class
962
class LinkListCell(CellBase):
963
    template_name = 'combo/link-list-cell.html'
964
    manager_form_template = 'combo/manager/link-list-cell-form.html'
965

  
966
    class Meta:
967
        verbose_name = _('List of links')
968

  
969
    @property
970
    def link_placeholder(self):
971
        return '_linkslist:{}'.format(self.pk)
972

  
973
    def get_items(self):
974
        return CellBase.get_cells(page=self.page, placeholder=self.link_placeholder)
975

  
976
    def get_cell_extra_context(self, context):
977
        render_skeleton = context.get('render_skeleton')
978
        request = context.get('request')
979
        extra_context = super(LinkListCell, self).get_cell_extra_context(context)
980
        extra_context['links'] = [item.get_cell_extra_context(context) for item in self.get_items()]
981
        return extra_context
982

  
983
    def get_link_cell_classes(self):
984
        return CellBase.get_cell_classes(lambda x: hasattr(x, 'add_as_link_label'))
985

  
986
    def get_default_form_class(self):
987
        from .forms import LinkListCellForm
988
        return LinkListCellForm
989

  
990
    def render_for_search(self):
991
        return ''
992

  
993
    def export_subobjects(self):
994
        return {'links': json.loads(
995
            serializers.serialize(
996
                'json',
997
                self.get_items(),
998
                use_natural_foreign_keys=True,
999
                use_natural_primary_keys=True)
1000
            )}
1001

  
1002
    def import_subobjects(self, cell_json):
1003
        for link in cell_json['links']:
1004
            link['fields']['placeholder'] = self.link_placeholder
1005
        for link in serializers.deserialize('json', json.dumps(cell_json['links'])):
1006
            link.save()
1007

  
1008
    def duplicate_m2m(self, new_cell):
1009
        # duplicate also link items
1010
        for link in self.get_items():
1011
            link.duplicate(page_target=new_cell.page, placeholder=new_cell.link_placeholder)
1012

  
1013

  
953 1014
@register_cell_class
954 1015
class FeedCell(CellBase):
955 1016
    title = models.CharField(_('Title'), max_length=150, blank=True)
combo/data/templates/combo/manager/link-list-cell-form.html
1
{% extends "combo/cell_form.html" %}
2
{% load i18n %}
3

  
4
{% block cell-form %}
5
{% with cell.get_items as links %}
6
{% if links %}
7
<table class="main">
8
  <tbody class="link-list" data-link-list-order-url="{% url 'combo-manager-link-list-order' page_pk=page.pk cell_reference=cell.get_reference %}">
9
    {% for link in links %}
10
    <tr class="link-item" data-link-item-id="{{ link.pk }}">
11
      <td><span class="handle-link-item">⣿</span> {{ link }}</td>
12
      <td>
13
        <a rel="popup" href="{% url 'combo-manager-page-list-cell-edit-link' page_pk=page.id cell_reference=cell.get_reference link_cell_reference=link.get_reference %}">{% trans "Edit" %}</a> |
14
        <a rel="popup" href="{% url 'combo-manager-page-list-cell-delete-link' page_pk=page.id cell_reference=cell.get_reference link_cell_reference=link.get_reference %}">{% trans "Delete" %}</a>
15
      </td>
16
    </tr>
17
    {% endfor %}
18
  </tbody>
19
</table>
20
{% endif %}
21
{% endwith %}
22
<div class="buttons">
23
  {% for klass in cell.get_link_cell_classes %}
24
  <a rel="popup" href="{% url 'combo-manager-page-list-cell-add-link' page_pk=page.id cell_reference=cell.get_reference link_code=klass.add_as_link_code %}">{{ klass.add_as_link_label }}</a> {% if not forloop.last %}|{% endif %}
25
  {% endfor %}
26
</div>
27
{% endblock %}
combo/manager/static/js/combo.manager.js
220 220
     return false;
221 221
  });
222 222

  
223
  $('.link-list').sortable({
224
     handle: '.handle-link-item',
225
     stop: function(event, ui) {
226
       var new_order = Object();
227
       $('.link-item').each(function(i, x) {
228
           var suffix = $(x).data('link-item-id');
229
           new_order['pos_' + suffix] = i;
230
       });
231
       $.ajax({
232
           url: $(this).data('link-list-order-url'),
233
           data: new_order
234
       });
235
     }
236
  });
237

  
223 238
  function compute_max_height($cell) {
224 239
    var cell_id = $cell.attr('id');
225 240
    $('style#for-' + cell_id).remove();
combo/manager/templates/combo/link_cell_form.html
1
{% extends "combo/manager_base.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
{% if form.instance.pk %}
6
<h2>{{ form.instance.edit_link_label }}</h2>
7
{% else %}
8
<h2>{{ form.instance.add_link_label }}</h2>
9
{% endif %}
10
{% endblock %}
11

  
12
{% block content %}
13

  
14
<form method="post" enctype="multipart/form-data">
15
  {% csrf_token %}
16
  {{ form.as_p }}
17
  <div class="buttons">
18
    <button class="submit-button">{% trans "Save" %}</button>
19
    <a class="cancel" href="{% url 'combo-manager-page-view' pk=form.instance.page_id %}">{% trans 'Cancel' %}</a>
20
  </div>
21
</form>
22
{% endblock %}
combo/manager/urls.py
75 75
            name='combo-manager-page-visibility-cell'),
76 76
        url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/label$',
77 77
            views.page_get_additional_label, name='combo-manager-page-get-additional-label'),
78
        url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/add-link/(?P<link_code>[\w-]+)$',
79
            views.page_list_cell_add_link,
80
            name='combo-manager-page-list-cell-add-link'),
81
        url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/link/(?P<link_cell_reference>[\w_-]+)/$',
82
            views.page_list_cell_edit_link,
83
            name='combo-manager-page-list-cell-edit-link'),
84
        url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/link/(?P<link_cell_reference>[\w_-]+)/delete$',
85
            views.page_list_cell_delete_link,
86
            name='combo-manager-page-list-cell-delete-link'),
87
        url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/order$',
88
            views.link_list_order,
89
            name='combo-manager-link-list-order'),
78 90
        url(r'^pages/(?P<page_pk>\d+)/order$', views.cell_order,
79 91
            name='combo-manager-cell-order'),
80 92
        url(r'^pages/order$', views.page_order,
combo/manager/views.py
33 33
from django.views.generic import (RedirectView, DetailView,
34 34
        CreateView, UpdateView, ListView, DeleteView, FormView)
35 35

  
36
from combo.data.models import Page, CellBase, ParentContentCell, PageSnapshot
36
from combo.data.models import Page, CellBase, ParentContentCell, PageSnapshot, LinkListCell
37 37
from combo.data.library import get_cell_class
38 38
from combo.data.utils import export_site, import_site, MissingGroups
39 39
from combo import plugins
......
124 124
        return super(CreateView, self).get_initial()
125 125

  
126 126
    def dispatch(self, request, *args, **kwargs):
127
        print(request.POST)
128 127
        self.parent = get_object_or_404(Page, pk=kwargs['pk'])
129 128
        return super(PageAddChildView, self).dispatch(request, *args, **kwargs)
130 129

  
......
564 563
    response = HttpResponse(content_type=content_type)
565 564
    response.write(json_str)
566 565
    return response
566

  
567

  
568
class PageListCellAddLinkView(CreateView):
569
    template_name = 'combo/link_cell_form.html'
570

  
571
    def dispatch(self, request, *args, **kwargs):
572
        try:
573
            self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk'])
574
        except LinkListCell.DoesNotExist:
575
            raise Http404
576
        for klass in self.cell.get_link_cell_classes():
577
            if klass.add_as_link_code == kwargs['link_code']:
578
                self.model = klass
579
                break
580
        if self.model is None:
581
            raise Http404
582
        return super(PageListCellAddLinkView, self).dispatch(request, *args, **kwargs)
583

  
584
    def get_form_class(self):
585
        return self.model().get_default_form_class()
586

  
587
    def get_form_kwargs(self):
588
        kwargs = super(PageListCellAddLinkView, self).get_form_kwargs()
589
        kwargs['instance'] = self.model(page=self.cell.page, placeholder=self.cell.link_placeholder)
590
        return kwargs
591

  
592
    def form_valid(self, form):
593
        orders = [x.order for x in self.cell.get_items()]
594
        if orders:
595
            form.instance.order = max(orders)+1
596
        else:
597
            form.instance.order = 1
598
        return super(PageListCellAddLinkView, self).form_valid(form)
599

  
600
    def get_success_url(self):
601
        return '%s#cell-%s' % (
602
            reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}),
603
            self.kwargs['cell_reference'])
604

  
605

  
606
page_list_cell_add_link = PageListCellAddLinkView.as_view()
607

  
608

  
609
class PageListCellEditLinkView(UpdateView):
610
    template_name = 'combo/link_cell_form.html'
611

  
612
    def dispatch(self, request, *args, **kwargs):
613
        try:
614
            self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk'])
615
        except LinkListCell.DoesNotExist:
616
            raise Http404
617
        try:
618
            self.object = CellBase.get_cell(kwargs['link_cell_reference'], page=kwargs['page_pk'])
619
        except ObjectDoesNotExist:
620
            raise Http404
621
        if self.object.placeholder != self.cell.link_placeholder:
622
            raise Http404
623
        self.model = self.object.__class__
624
        return super(PageListCellEditLinkView, self).dispatch(request, *args, **kwargs)
625

  
626
    def get_object(self, *args, **kwargs):
627
        return self.object
628

  
629
    def get_form_class(self):
630
        return self.model().get_default_form_class()
631

  
632
    def form_valid(self, form):
633
        if self.request.is_ajax():
634
            self.object = form.save()
635
            response = self.form_invalid(form)  # avoid redirection
636
        else:
637
            response = super(PageListCellEditLinkView, self).form_valid(form)
638
        PageSnapshot.take(self.cell.page, request=self.request, comment=_('changed cell "%s"') % self.cell)
639
        return response
640

  
641
    def get_success_url(self):
642
        return '%s#cell-%s' % (
643
            reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}),
644
            self.kwargs['cell_reference'])
645

  
646

  
647
page_list_cell_edit_link = PageListCellEditLinkView.as_view()
648

  
649

  
650
class PageListCellDeleteLinkView(DeleteView):
651
    template_name = 'combo/generic_confirm_delete.html'
652

  
653
    def dispatch(self, request, *args, **kwargs):
654
        try:
655
            self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk'])
656
        except LinkListCell.DoesNotExist:
657
            raise Http404
658
        try:
659
            self.object = CellBase.get_cell(kwargs['link_cell_reference'], page=kwargs['page_pk'])
660
        except ObjectDoesNotExist:
661
            raise Http404
662
        if self.object.placeholder != self.cell.link_placeholder:
663
            raise Http404
664
        self.model = self.object.__class__
665
        return super(PageListCellDeleteLinkView, self).dispatch(request, *args, **kwargs)
666

  
667
    def get_object(self, *args, **kwargs):
668
        return self.object
669

  
670
    def delete(self, request, *args, **kwargs):
671
        response = super(PageListCellDeleteLinkView, self).delete(request, *args, **kwargs)
672
        PageSnapshot.take(self.cell.page, request=self.request, comment=_('changed cell "%s"') % self.cell)
673
        return response
674

  
675
    def get_success_url(self):
676
        return '%s#cell-%s' % (
677
            reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}),
678
            self.kwargs['cell_reference'])
679

  
680

  
681
page_list_cell_delete_link = PageListCellDeleteLinkView.as_view()
682

  
683

  
684
def link_list_order(request, page_pk, cell_reference):
685
    try:
686
        cell = CellBase.get_cell(cell_reference, page=page_pk)
687
    except LinkListCell.DoesNotExist:
688
        raise Http404
689

  
690
    has_changes = False
691
    for link in cell.get_items():
692
        old_order = link.order
693
        try:
694
            new_order = int(request.GET.get('pos_' + str(link.pk)))
695
        except TypeError:
696
            continue
697
        if new_order != old_order:
698
            link.order = new_order
699
            has_changes = True
700
            link.save(update_fields=['order'])
701

  
702
    if has_changes:
703
        PageSnapshot.take(cell.page, request=request, comment=_('reordered cells'))
704

  
705
    return HttpResponse(status=204)
combo/public/templates/combo/link-list-cell.html
1
{% block cell-content %}
2
{% spaceless %}
3
{% if links %}
4
<ul>
5
{% for link in links %}
6
  <li><a href="{{ link.url }}">{{ link.title }}</a></li>
7
{% endfor %}
8
</ul>
9
{% endif %}
10
{% endspaceless %}
11
{% endblock %}
tests/test_cells.py
4 4
import pytest
5 5
import requests
6 6

  
7
from combo.data.models import Page, CellBase, TextCell, LinkCell, MenuCell, JsonCellBase, JsonCell, ConfigJsonCell
7
from combo.data.models import (
8
    Page, CellBase, TextCell, LinkCell, MenuCell, JsonCellBase,
9
    JsonCell, ConfigJsonCell, LinkListCell
10
)
8 11
from django.conf import settings
9 12
from django.db import connection
10 13
from django.forms.widgets import Media
......
93 96
    assert 'href=""' in cell.render(ctx)
94 97
    assert 'href="/plop"' in cell.render(ctx)
95 98

  
99

  
96 100
def test_link_cell():
97 101
    page = Page(title='example page', slug='example-page')
98 102
    page.save()
......
130 134
    assert cell.render(ctx).strip() == '<a href="http://example.net/#anchor">altertitle</a>'
131 135

  
132 136

  
137
def test_link_list_cell():
138
    page = Page.objects.create(title='example page', slug='example-page')
139

  
140
    cell = LinkListCell.objects.create(order=0, page=page)
141
    item = LinkCell.objects.create(
142
        page=page,
143
        placeholder=cell.link_placeholder,
144
        title='Example Site',
145
        url='http://example.net/',
146
        order=0,
147
    )
148

  
149
    ctx = {}
150
    assert cell.render(ctx).strip() == '<ul><li><a href="http://example.net/">Example Site</a></li></ul>'
151

  
152
    item.title = ''
153
    item.save()
154
    assert cell.render(ctx).strip() == '<ul><li><a href="http://example.net/">http://example.net/</a></li></ul>'
155

  
156
    item.link_page = page
157
    item.save()
158
    assert cell.render(ctx).strip() == '<ul><li><a href="/example-page/">example page</a></li></ul>'
159

  
160
    item.title = 'altertitle'
161
    item.save()
162
    assert cell.render(ctx).strip() == '<ul><li><a href="/example-page/">altertitle</a></li></ul>'
163

  
164
    item.anchor = 'anchor'
165
    item.save()
166
    assert cell.render(ctx).strip() == '<ul><li><a href="/example-page/#anchor">altertitle</a></li></ul>'
167

  
168
    item.link_page = None
169
    item.save()
170
    assert cell.render(ctx).strip() == '<ul><li><a href="http://example.net/#anchor">altertitle</a></li></ul>'
171

  
172

  
133 173
def test_menu_cell():
134 174
    Page.objects.all().delete()
135 175
    parent = page = Page(title='Page1', slug='page1', template_name='standard')
......
728 768

  
729 769
    TextCell(page=page, placeholder='content', order=0, text='hello').save()
730 770
    assert set(Page.objects.get(id=page.id).related_cells['cell_types']) == set(['data_textcell', 'data_linkcell'])
771

  
772

  
773
def test_link_list_cell_duplicate():
774
    page = Page.objects.create(title='xxx', slug='new', template_name='standard')
775
    cell = LinkListCell.objects.create(order=0, page=page)
776
    item = LinkCell.objects.create(
777
        page=page,
778
        placeholder=cell.link_placeholder,
779
        title='Example Site',
780
        url='http://example.net/',
781
        link_page=page,
782
        order=1,
783
    )
784

  
785
    new_cell = cell.duplicate()
786
    assert LinkCell.objects.count() == 2
787
    assert len(new_cell.get_items()) == 1
788
    new_item = new_cell.get_items()[0]
789
    assert new_item.page == page
790
    assert new_item.placeholder == new_cell.link_placeholder
791
    assert new_item.pk != item.pk
792
    assert new_item.title == item.title
793
    assert new_item.url == item.url
794
    assert new_item.link_page == item.link_page
tests/test_manager.py
21 21
from webtest import Upload
22 22

  
23 23
from combo.wsgi import application
24
from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot
24
from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot, LinkListCell
25 25
from combo.apps.assets.models import Asset
26 26
from combo.apps.family.models import FamilyInfosCell
27 27
from combo.apps.search.models import SearchCell
......
1373 1373
    assert 'syntax error' not in resp.text
1374 1374
    assert JsonCell.objects.count() == 1
1375 1375
    assert JsonCell.objects.first().template_string == '{{ ok }}'
1376

  
1377

  
1378
def test_add_edit_delete_list_link_item(app, admin_user):
1379
    Page.objects.all().delete()
1380
    page = Page.objects.create(title='One', slug='one', template_name='standard')
1381
    cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
1382
    app = login(app)
1383
    resp = app.get('/manage/pages/%s/' % page.pk)
1384

  
1385
    resp = resp.click(href='.*/add-link/link$')
1386
    resp.forms[0]['title'] = 'Hello world'
1387
    resp.forms[0]['url'] = 'http://example.com'
1388
    resp = resp.forms[0].submit()
1389
    assert resp.status_int == 302
1390
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
1391
    assert LinkCell.objects.count() == 1
1392
    item = LinkCell.objects.get()
1393
    assert item.title == 'Hello world'
1394
    assert item.url == 'http://example.com'
1395
    assert item.page == page
1396
    assert item.placeholder == cell.link_placeholder
1397

  
1398
    resp = resp.follow()
1399
    resp = resp.click(href='.*/link/%s/$' % item.get_reference())
1400
    resp.forms[0]['title'] = 'Hello world 2'
1401
    resp.forms[0]['url'] = 'http://example2.com'
1402
    resp = resp.forms[0].submit()
1403
    assert resp.status_int == 302
1404
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
1405
    assert LinkCell.objects.count() == 1
1406
    item.refresh_from_db()
1407
    assert item.title == 'Hello world 2'
1408
    assert item.url == 'http://example2.com'
1409

  
1410
    resp = resp.follow()
1411
    resp = resp.click(href='.*/link/%s/delete' % item.get_reference())
1412
    resp = resp.forms[0].submit()
1413
    assert resp.status_int == 302
1414
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
1415
    assert LinkCell.objects.count() == 0
1416

  
1417

  
1418
def test_edit_link_list_order(app, admin_user):
1419
    Page.objects.all().delete()
1420
    page = Page.objects.create(title='One', slug='one', template_name='standard')
1421
    cell = LinkListCell.objects.create(order=0, page=page)
1422
    items = []
1423
    for i in range(5):
1424
        items.append(
1425
            LinkCell.objects.create(
1426
                page=page,
1427
                placeholder=cell.link_placeholder,
1428
                title='Foo %s' % i,
1429
                url='http://example.net/',
1430
                link_page=page,
1431
                order=i+1,
1432
            )
1433
        )
1434

  
1435
    params = []
1436
    new_order = [2, 3, 1, 4, 5]
1437
    for i, (item, new_pos) in enumerate(zip(items, new_order)):
1438
        params.append(('pos_%s' % item.pk, str(new_pos)))
1439

  
1440
    app = login(app)
1441
    resp = app.get('/manage/pages/%s/cell/%s/order?%s' % (page.pk, cell.get_reference(), urlencode(params)))
1442
    assert resp.status_code == 204
1443
    for i, item in enumerate(items):
1444
        item.refresh_from_db()
1445
        assert item.order == new_order[i]
tests/test_pages.py
9 9
from django.test.client import RequestFactory
10 10
from django.utils.six import StringIO
11 11
from django.utils.timezone import now
12
from combo.data.models import Page, PageSnapshot, CellBase, TextCell, LinkCell
12
from combo.data.models import Page, PageSnapshot, CellBase, TextCell, LinkCell, LinkListCell
13 13
from combo.data.management.commands.import_site import Command as ImportSiteCommand
14 14
from combo.data.management.commands.export_site import Command as ExportSiteCommand
15 15
from combo.manager.forms import PageVisibilityForm
......
182 182
    cell2 = LinkCell(page=page2, title='foo', placeholder='content', link_page=page, order=1)
183 183
    cell2.save()
184 184

  
185
    cell3 = LinkListCell.objects.create(page=page, placeholder='content', order=2)
186
    item1 = LinkCell.objects.create(
187
        page=page,
188
        placeholder=cell3.link_placeholder,
189
        title='Example Site',
190
        url='http://example.net/',
191
        order=0,
192
    )
193
    item2 = LinkCell.objects.create(
194
        page=page,
195
        placeholder=cell3.link_placeholder,
196
        title='blah',
197
        link_page=page2,
198
        order=1,
199
    )
200

  
185 201
    site_export = [x.get_serialized_page() for x in Page.objects.all()]
186 202
    Page.objects.all().delete()
187 203

  
......
189 205

  
190 206
    new_page_1 = Page.objects.all().order_by('order')[0]
191 207
    new_page_2 = Page.objects.all().order_by('order')[1]
192
    assert CellBase.get_cells(page_id=new_page_1.id)[0].link_page_id == new_page_2.id
193
    assert CellBase.get_cells(page_id=new_page_2.id)[0].link_page_id == new_page_1.id
208
    new_cells_1 = CellBase.get_cells(page_id=new_page_1.id, placeholder='content')
209
    new_cells_2 = CellBase.get_cells(page_id=new_page_2.id, placeholder='content')
210
    assert new_cells_1[0].link_page_id == new_page_2.id
211
    assert new_cells_2[0].link_page_id == new_page_1.id
212
    assert len(new_cells_1[1].get_items()) == 2
213
    new_item_1 = new_cells_1[1].get_items()[0]
214
    assert isinstance(new_item_1, LinkCell)
215
    assert new_item_1.title == item1.title
216
    assert new_item_1.url == item1.url
217
    assert new_item_1.link_page is None
218
    new_item_2 = new_cells_1[1].get_items()[1]
219
    assert isinstance(new_item_2, LinkCell)
220
    assert new_item_2.title == item2.title
221
    assert new_item_2.url == ''
222
    assert new_item_2.link_page == new_page_2
194 223

  
195 224

  
196 225
def test_duplicate_page():
tests/test_wcs.py
22 22

  
23 23
import mock
24 24

  
25
from combo.data.models import Page
25
from combo.data.models import CellBase, LinkListCell, Page
26 26
from combo.apps.search.engines import engines
27 27
from combo.apps.wcs.models import (WcsFormCell, WcsCurrentFormsCell,
28 28
        WcsFormsOfCategoryCell, WcsCurrentDraftsCell, WcsCategoryCell,
......
901 901

  
902 902
    result = cell.render(context)
903 903
    assert '/backoffice/submission/a-private-form/' in result
904

  
905

  
906
@wcs_present
907
def test_manager_link_list_cell_duplicate():
908
    page = Page.objects.create(title='xxx', slug='new', template_name='standard')
909
    cell = LinkListCell.objects.create(order=0, page=page)
910
    item = WcsFormCell.objects.create(
911
        page=page,
912
        placeholder=cell.link_placeholder,
913
        cached_title='A title',
914
        cached_url='http://example.com',
915
        cached_json={'foo': 'bar'},
916
        order=1)
917

  
918
    new_cell = cell.duplicate()
919
    assert WcsFormCell.objects.count() == 2
920
    assert len(new_cell.get_items()) == 1
921
    new_item = new_cell.get_items()[0]
922
    assert new_item.page == page
923
    assert new_item.placeholder == new_cell.link_placeholder
924
    assert new_item.pk != item.pk
925
    assert new_item.cached_title == item.cached_title
926
    assert new_item.cached_url == item.cached_url
927
    assert new_item.cached_json == item.cached_json
928

  
929

  
930
@wcs_present
931
def test_manager_add_edit_delete_list_link_item(app, admin_user):
932
    Page.objects.all().delete()
933
    page = Page.objects.create(title='One', slug='one', template_name='standard')
934
    cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
935
    app = login(app)
936
    resp = app.get('/manage/pages/%s/' % page.pk)
937

  
938
    resp = resp.click(href='.*/add-link/form-link$')
939
    resp.forms[0]['formdef_reference'] = 'default:form-title'
940
    resp = resp.forms[0].submit()
941
    assert resp.status_int == 302
942
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
943
    assert WcsFormCell.objects.count() == 1
944
    item = WcsFormCell.objects.get()
945
    assert item.formdef_reference == 'default:form-title'
946
    assert item.page == page
947
    assert item.placeholder == cell.link_placeholder
948

  
949
    resp = resp.follow()
950
    resp = resp.click(href='.*/link/%s/$' % item.get_reference())
951
    resp.forms[0]['formdef_reference'] = 'default:a-private-form'
952
    resp = resp.forms[0].submit()
953
    assert resp.status_int == 302
954
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
955
    assert WcsFormCell.objects.count() == 1
956
    item.refresh_from_db()
957
    assert item.formdef_reference == 'default:a-private-form'
958

  
959
    resp = resp.follow()
960
    resp = resp.click(href='.*/link/%s/delete' % item.get_reference())
961
    resp = resp.forms[0].submit()
962
    assert resp.status_int == 302
963
    assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
964
    assert WcsFormCell.objects.count() == 0
965

  
966

  
967
def test_import_export_pages_with_links():
968
    page = Page(title=u'bar', slug='bar', order=1)
969
    page.save()
970

  
971
    cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
972
    item = WcsFormCell.objects.create(
973
        page=page,
974
        placeholder=cell.link_placeholder,
975
        cached_title='A title',
976
        cached_url='http://example.com',
977
        cached_json={'foo': 'bar'},
978
        order=0,
979
    )
980

  
981
    site_export = [x.get_serialized_page() for x in Page.objects.all()]
982
    Page.objects.all().delete()
983

  
984
    Page.load_serialized_pages(site_export)
985

  
986
    new_page = Page.objects.get()
987
    new_cells = CellBase.get_cells(page_id=new_page.id, placeholder='content')
988
    assert len(new_cells[0].get_items()) == 1
989
    new_item = new_cells[0].get_items()[0]
990
    assert isinstance(new_item, WcsFormCell)
991
    assert new_item.cached_title == item.cached_title
992
    assert new_item.cached_url == item.cached_url
993
    assert new_item.cached_json == item.cached_json
904
-