Projet

Général

Profil

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

Lauréline Guérin, 16 janvier 2020 09:43

Télécharger (35,3 ko)

Voir les différences:

Subject: [PATCH] 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  |  39 +++++
 combo/data/models.py                          |  80 +++++++++-
 .../combo/manager/link-list-cell-form.html    |  46 ++++++
 combo/manager/static/css/combo.manager.css    |  38 +++++
 .../templates/combo/link_cell_form.html       |  22 +++
 combo/manager/urls.py                         |  12 ++
 combo/manager/views.py                        | 144 +++++++++++++++++-
 .../templates/combo/link-list-cell.html       |  12 ++
 tests/test_cells.py                           |  61 +++++++-
 tests/test_manager.py                         |  72 ++++++++-
 tests/test_pages.py                           |  35 ++++-
 tests/test_wcs.py                             |  92 ++++++++++-
 14 files changed, 662 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 = ['title']
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
                ('title', models.CharField(max_length=150, verbose_name='Title', blank=True)),
29
            ],
30
            options={
31
                'verbose_name': 'List of links',
32
            },
33
        ),
34
        migrations.AddField(
35
            model_name='linklistcell',
36
            name='page',
37
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page'),
38
        ),
39
    ]
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
    title = models.CharField(_('Title'), max_length=150, blank=True)
964

  
965
    template_name = 'combo/link-list-cell.html'
966
    manager_form_template = 'combo/manager/link-list-cell-form.html'
967

  
968
    class Meta:
969
        verbose_name = _('List of links')
970

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

  
975
    def get_items(self):
976
        return CellBase.get_cells(
977
            page=self.page,
978
            placeholder=self.link_placeholder,
979
            cell_filter=lambda x: hasattr(x, 'add_as_link_label'))
980

  
981
    def get_additional_label(self):
982
        title = self.title
983
        if not title:
984
            return None
985
        return utils.ellipsize(title)
986

  
987
    def get_cell_extra_context(self, context):
988
        extra_context = super(LinkListCell, self).get_cell_extra_context(context)
989
        links = []
990
        for cell in context.get('page_cells', []):
991
            if not hasattr(cell, 'add_as_link_label'):
992
                continue
993
            if not cell.placeholder == self.link_placeholder:
994
                continue
995
            links.append(cell.get_cell_extra_context(context))
996
        extra_context['links'] = links
997
        extra_context['title'] = self.title
998
        return extra_context
999

  
1000
    def get_link_cell_classes(self):
1001
        return CellBase.get_cell_classes(lambda x: hasattr(x, 'add_as_link_label'))
1002

  
1003
    def get_default_form_class(self):
1004
        from .forms import LinkListCellForm
1005
        return LinkListCellForm
1006

  
1007
    def render_for_search(self):
1008
        return ''
1009

  
1010
    def export_subobjects(self):
1011
        return {'links': json.loads(
1012
            serializers.serialize(
1013
                'json',
1014
                self.get_items(),
1015
                use_natural_foreign_keys=True,
1016
                use_natural_primary_keys=True)
1017
            )}
1018

  
1019
    def import_subobjects(self, cell_json):
1020
        for link in cell_json['links']:
1021
            link['fields']['placeholder'] = self.link_placeholder
1022
        for link in serializers.deserialize('json', json.dumps(cell_json['links'])):
1023
            link.save()
1024

  
1025
    def duplicate_m2m(self, new_cell):
1026
        # duplicate also link items
1027
        for link in self.get_items():
1028
            link.duplicate(page_target=new_cell.page, placeholder=new_cell.link_placeholder)
1029

  
1030

  
953 1031
@register_cell_class
954 1032
class FeedCell(CellBase):
955 1033
    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
{{ form.as_p }}
6
{% with cell.get_items as links %}
7
{% if links %}
8
<p><label>{% trans "Links:" %}</label></p>
9
<div>
10
 <ul class="objects-list list-of-links" id="list-of-links-{{ cell.pk }}"
11
     data-link-list-order-url="{% url 'combo-manager-link-list-order' page_pk=page.pk cell_reference=cell.get_reference %}">
12
   {% for link in links %}
13
   <li data-link-item-id="{{ link.pk }}"><span class="handle">⣿</span>
14
   <span title="{{ link }}">{{ link|truncatechars:100 }}</span>
15
       <a rel="popup" title="{% trans "Edit" %}" class="link-action-icon edit" 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>
16
       <a rel="popup" title="{% trans "Delete" %}" class="link-action-icon delete" 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>
17
   </li>
18
   {% endfor %}
19
 </ul>
20
</div>
21
<script>
22
$(function () {
23
  $('#list-of-links-{{ cell.pk }}').sortable({
24
    handle: '.handle',
25
    update: function(event, ui) {
26
       var new_order = Object();
27
       $(this).find('li').each(function(i, x) {
28
           var suffix = $(x).data('link-item-id');
29
           new_order['pos_' + suffix] = i;
30
       });
31
       $.ajax({
32
           url: $(this).data('link-list-order-url'),
33
           data: new_order
34
       });
35
    }
36
  });
37
});
38
</script>
39
{% endif %}
40
{% endwith %}
41
<div class="buttons">
42
  {% for klass in cell.get_link_cell_classes %}
43
  <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 %}
44
  {% endfor %}
45
</div>
46
{% endblock %}
combo/manager/static/css/combo.manager.css
476 476
	text-align: center;
477 477
	padding: 45px 1ex 1ex 1ex;
478 478
}
479

  
480
ul.objects-list.list-of-links li {
481
	padding-left: 0;
482
}
483

  
484
ul.objects-list.list-of-links li a.link-action-icon {
485
	height: 100%;
486
	position: absolute;
487
	right: 0;
488
	top: 0;
489
	width: 3em;
490
	display: block;
491
	overflow: hidden;
492
	text-decoration: none;
493
	border: none;
494
	text-indent: -1000px;
495
	line-height: 3em;
496
}
497

  
498
ul.objects-list.list-of-links li a.link-action-icon::before {
499
	font-family: FontAwesome;
500
	text-indent: 0px;
501
	text-align: center;
502
	display: block;
503
	width: 100%;
504
}
505

  
506
ul.objects-list.list-of-links li a.link-action-icon.delete::before {
507
	content: "\f057"; /* remove-sign */
508
}
509

  
510
ul.objects-list.list-of-links li a.link-action-icon.edit {
511
	right: 3em;
512
}
513

  
514
ul.objects-list.list-of-links li a.link-action-icon.edit::before {
515
	content: "\f044";
516
}
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

  
......
399 398
    def get_context_data(self, **kwargs):
400 399
        context = super(PageEditCellView, self).get_context_data(**kwargs)
401 400
        context['cell'] = self.get_object()
401
        context['page'] = context['cell'].page
402 402
        return context
403 403

  
404 404
    def get_object(self, queryset=None):
......
564 564
    response = HttpResponse(content_type=content_type)
565 565
    response.write(json_str)
566 566
    return response
567

  
568

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

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

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

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

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

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

  
606

  
607
page_list_cell_add_link = PageListCellAddLinkView.as_view()
608

  
609

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

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

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

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

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

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

  
647

  
648
page_list_cell_edit_link = PageListCellEditLinkView.as_view()
649

  
650

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

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

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

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

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

  
681

  
682
page_list_cell_delete_link = PageListCellDeleteLinkView.as_view()
683

  
684

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

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

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

  
706
    return HttpResponse(status=204)
combo/public/templates/combo/link-list-cell.html
1
{% block cell-content %}
2
{% spaceless %}
3
<div class="links-list">
4
  {% if title %}<h2>{{title}}</h2>{% endif %}
5
  <ul>
6
  {% for link in links %}
7
    <li><a href="{{ link.url }}">{{ link.title }}</a></li>
8
  {% endfor %}
9
  </ul>
10
</div>
11
{% endspaceless %}
12
{% 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 = {'page_cells': [item]}
150
    assert '<ul><li><a href="http://example.net/">Example Site</a></li></ul>' in cell.render(ctx)
151

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

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

  
158
    item.title = 'altertitle'
159
    assert '<ul><li><a href="/example-page/">altertitle</a></li></ul>' in cell.render(ctx)
160

  
161
    item.anchor = 'anchor'
162
    assert '<ul><li><a href="/example-page/#anchor">altertitle</a></li></ul>' in cell.render(ctx)
163

  
164
    item.link_page = None
165
    assert '<ul><li><a href="http://example.net/#anchor">altertitle</a></li></ul>' in cell.render(ctx)
166

  
167

  
133 168
def test_menu_cell():
134 169
    Page.objects.all().delete()
135 170
    parent = page = Page(title='Page1', slug='page1', template_name='standard')
......
728 763

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

  
767

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

  
780
    new_cell = cell.duplicate()
781
    assert LinkCell.objects.count() == 2
782
    assert len(new_cell.get_items()) == 1
783
    new_item = new_cell.get_items()[0]
784
    assert new_item.page == page
785
    assert new_item.placeholder == new_cell.link_placeholder
786
    assert new_item.pk != item.pk
787
    assert new_item.title == item.title
788
    assert new_item.url == item.url
789
    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
-