diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py index 1b722590..f17da120 100644 --- a/combo/apps/wcs/models.py +++ b/combo/apps/wcs/models.py @@ -36,14 +36,18 @@ from .utils import get_wcs_json, is_wcs_enabled, get_wcs_services @register_cell_class class WcsFormCell(CellBase): - template_name = 'combo/wcs/form.html' - formdef_reference = models.CharField(_('Form'), max_length=150) cached_title = models.CharField(_('Title'), max_length=150) cached_url = models.URLField(_('URL')) cached_json = JSONField(blank=True) + template_name = 'combo/wcs/form.html' + add_as_link_label = _('add a form link') + add_link_label = _('New form link') + edit_link_label = _('Edit form link') + add_as_link_code = 'form-link' + is_enabled = classmethod(is_wcs_enabled) class Meta: diff --git a/combo/data/forms.py b/combo/data/forms.py index ffd4c92a..5ca614f2 100644 --- a/combo/data/forms.py +++ b/combo/data/forms.py @@ -18,7 +18,7 @@ import copy from django import forms -from .models import Page, ParametersCell, MenuCell, LinkCell, ConfigJsonCell +from .models import Page, ParametersCell, MenuCell, LinkCell, LinkListCell, ConfigJsonCell from jsonfield.widgets import JSONWidget from combo.utils import cache_during_request @@ -41,6 +41,7 @@ class ParametersForm(forms.Form): break return self.cleaned_data + class ParametersCellForm(forms.ModelForm): class Meta: model = ParametersCell @@ -61,6 +62,7 @@ def get_page_choices(): pages = Page.get_as_reordered_flat_hierarchy(Page.objects.all()) return [(x.id, '%s %s' % (u'\u00a0' * x.level * 2, x.title)) for x in pages] + class MenuCellForm(forms.ModelForm): class Meta: model = MenuCell @@ -82,6 +84,15 @@ class LinkCellForm(forms.ModelForm): choices=[(None, '-----')] + get_page_choices()) +class LinkListCellForm(forms.ModelForm): + class Meta: + model = LinkListCell + fields = ['title'] + + def __init__(self, *args, **kwargs): + super(LinkListCellForm, self).__init__(*args, **kwargs) + + class ConfigJsonForm(forms.ModelForm): formdef = [] diff --git a/combo/data/migrations/0039_link_list_cell.py b/combo/data/migrations/0039_link_list_cell.py new file mode 100644 index 00000000..78fa3415 --- /dev/null +++ b/combo/data/migrations/0039_link_list_cell.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ('data', '0038_increase_jsoncell_url_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='LinkListCell', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('placeholder', models.CharField(max_length=20)), + ('order', models.PositiveIntegerField()), + ('slug', models.SlugField(blank=True, verbose_name='Slug')), + ('extra_css_class', models.CharField(blank=True, max_length=100, verbose_name='Extra classes for CSS styling')), + ('public', models.BooleanField(default=True, verbose_name='Public')), + ('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')), + ('last_update_timestamp', models.DateTimeField(auto_now=True)), + ('groups', models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups')), + ('title', models.CharField(max_length=150, verbose_name='Title', blank=True)), + ], + options={ + 'verbose_name': 'List of links', + }, + ), + migrations.AddField( + model_name='linklistcell', + name='page', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page'), + ), + ] diff --git a/combo/data/models.py b/combo/data/models.py index 372726f2..bd84afe4 100644 --- a/combo/data/models.py +++ b/combo/data/models.py @@ -451,6 +451,8 @@ class Page(models.Model): new_page.groups.set(self.groups.all()) for cell in self.get_cells(): + if cell.placeholder and cell.placeholder.startswith('_'): + continue cell.duplicate(page_target=new_page) return new_page @@ -756,12 +758,14 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)): def import_subobjects(self, cell_json): pass - def duplicate(self, page_target=None): + def duplicate(self, page_target=None, placeholder=None): # clone current cell new_cell = copy.deepcopy(self) new_cell.pk = None # set page new_cell.page = page_target or self.page + # set placeholder + new_cell.placeholder = placeholder or new_cell.placeholder # store new cell new_cell.save() @@ -905,6 +909,10 @@ class LinkCell(CellBase): anchor = models.CharField(_('Anchor'), max_length=150, blank=True) template_name = 'combo/link-cell.html' + add_as_link_label = _('add a link') + add_link_label = _('New link') + edit_link_label = _('Edit link') + add_as_link_code = 'link' class Meta: verbose_name = _('Link') @@ -950,6 +958,76 @@ class LinkCell(CellBase): return [] +@register_cell_class +class LinkListCell(CellBase): + title = models.CharField(_('Title'), max_length=150, blank=True) + + template_name = 'combo/link-list-cell.html' + manager_form_template = 'combo/manager/link-list-cell-form.html' + + class Meta: + verbose_name = _('List of links') + + @property + def link_placeholder(self): + return '_linkslist:{}'.format(self.pk) + + def get_items(self): + return CellBase.get_cells( + page=self.page, + placeholder=self.link_placeholder, + cell_filter=lambda x: hasattr(x, 'add_as_link_label')) + + def get_additional_label(self): + title = self.title + if not title: + return None + return utils.ellipsize(title) + + def get_cell_extra_context(self, context): + extra_context = super(LinkListCell, self).get_cell_extra_context(context) + links = [] + for cell in context.get('page_cells', []): + if not hasattr(cell, 'add_as_link_label'): + continue + if not cell.placeholder == self.link_placeholder: + continue + links.append(cell.get_cell_extra_context(context)) + extra_context['links'] = links + extra_context['title'] = self.title + return extra_context + + def get_link_cell_classes(self): + return CellBase.get_cell_classes(lambda x: hasattr(x, 'add_as_link_label')) + + def get_default_form_class(self): + from .forms import LinkListCellForm + return LinkListCellForm + + def render_for_search(self): + return '' + + def export_subobjects(self): + return {'links': json.loads( + serializers.serialize( + 'json', + self.get_items(), + use_natural_foreign_keys=True, + use_natural_primary_keys=True) + )} + + def import_subobjects(self, cell_json): + for link in cell_json['links']: + link['fields']['placeholder'] = self.link_placeholder + for link in serializers.deserialize('json', json.dumps(cell_json['links'])): + link.save() + + def duplicate_m2m(self, new_cell): + # duplicate also link items + for link in self.get_items(): + link.duplicate(page_target=new_cell.page, placeholder=new_cell.link_placeholder) + + @register_cell_class class FeedCell(CellBase): title = models.CharField(_('Title'), max_length=150, blank=True) diff --git a/combo/data/templates/combo/manager/link-list-cell-form.html b/combo/data/templates/combo/manager/link-list-cell-form.html new file mode 100644 index 00000000..a0688acb --- /dev/null +++ b/combo/data/templates/combo/manager/link-list-cell-form.html @@ -0,0 +1,46 @@ +{% extends "combo/cell_form.html" %} +{% load i18n %} + +{% block cell-form %} +{{ form.as_p }} +{% with cell.get_items as links %} +{% if links %} +

+
+ +
+ +{% endif %} +{% endwith %} +
+ {% for klass in cell.get_link_cell_classes %} + {{ klass.add_as_link_label }} {% if not forloop.last %}|{% endif %} + {% endfor %} +
+{% endblock %} diff --git a/combo/manager/static/css/combo.manager.css b/combo/manager/static/css/combo.manager.css index 0f8bfc0d..eaf78645 100644 --- a/combo/manager/static/css/combo.manager.css +++ b/combo/manager/static/css/combo.manager.css @@ -480,3 +480,41 @@ ul.gallery li:last-child a { text-align: center; padding: 45px 1ex 1ex 1ex; } + +ul.objects-list.list-of-links li { + padding-left: 0; +} + +ul.objects-list.list-of-links li a.link-action-icon { + height: 100%; + position: absolute; + right: 0; + top: 0; + width: 3em; + display: block; + overflow: hidden; + text-decoration: none; + border: none; + text-indent: -1000px; + line-height: 3em; +} + +ul.objects-list.list-of-links li a.link-action-icon::before { + font-family: FontAwesome; + text-indent: 0px; + text-align: center; + display: block; + width: 100%; +} + +ul.objects-list.list-of-links li a.link-action-icon.delete::before { + content: "\f057"; /* remove-sign */ +} + +ul.objects-list.list-of-links li a.link-action-icon.edit { + right: 3em; +} + +ul.objects-list.list-of-links li a.link-action-icon.edit::before { + content: "\f044"; +} diff --git a/combo/manager/templates/combo/link_cell_form.html b/combo/manager/templates/combo/link_cell_form.html new file mode 100644 index 00000000..c7022516 --- /dev/null +++ b/combo/manager/templates/combo/link_cell_form.html @@ -0,0 +1,22 @@ +{% extends "combo/manager_base.html" %} +{% load i18n %} + +{% block appbar %} +{% if form.instance.pk %} +

{{ form.instance.edit_link_label }}

+{% else %} +

{{ form.instance.add_link_label }}

+{% endif %} +{% endblock %} + +{% block content %} + +
+ {% csrf_token %} + {{ form.as_p }} +
+ + {% trans 'Cancel' %} +
+
+{% endblock %} diff --git a/combo/manager/urls.py b/combo/manager/urls.py index 66d34eef..a3f55e44 100644 --- a/combo/manager/urls.py +++ b/combo/manager/urls.py @@ -75,6 +75,18 @@ urlpatterns = [ name='combo-manager-page-visibility-cell'), url(r'^pages/(?P\d+)/cell/(?P[\w_-]+)/label$', views.page_get_additional_label, name='combo-manager-page-get-additional-label'), + url(r'^pages/(?P\d+)/cell/(?P[\w_-]+)/add-link/(?P[\w-]+)$', + views.page_list_cell_add_link, + name='combo-manager-page-list-cell-add-link'), + url(r'^pages/(?P\d+)/cell/(?P[\w_-]+)/link/(?P[\w_-]+)/$', + views.page_list_cell_edit_link, + name='combo-manager-page-list-cell-edit-link'), + url(r'^pages/(?P\d+)/cell/(?P[\w_-]+)/link/(?P[\w_-]+)/delete$', + views.page_list_cell_delete_link, + name='combo-manager-page-list-cell-delete-link'), + url(r'^pages/(?P\d+)/cell/(?P[\w_-]+)/order$', + views.link_list_order, + name='combo-manager-link-list-order'), url(r'^pages/(?P\d+)/order$', views.cell_order, name='combo-manager-cell-order'), url(r'^pages/order$', views.page_order, diff --git a/combo/manager/views.py b/combo/manager/views.py index 5992fa2f..8977bc95 100644 --- a/combo/manager/views.py +++ b/combo/manager/views.py @@ -33,7 +33,7 @@ from django.views.decorators.csrf import requires_csrf_token from django.views.generic import (RedirectView, DetailView, CreateView, UpdateView, ListView, DeleteView, FormView) -from combo.data.models import Page, CellBase, ParentContentCell, PageSnapshot +from combo.data.models import Page, CellBase, ParentContentCell, PageSnapshot, LinkListCell from combo.data.library import get_cell_class from combo.data.utils import export_site, import_site, MissingGroups from combo import plugins @@ -124,7 +124,6 @@ class PageAddChildView(PageAddView): return super(CreateView, self).get_initial() def dispatch(self, request, *args, **kwargs): - print(request.POST) self.parent = get_object_or_404(Page, pk=kwargs['pk']) return super(PageAddChildView, self).dispatch(request, *args, **kwargs) @@ -399,6 +398,7 @@ class PageEditCellView(UpdateView): def get_context_data(self, **kwargs): context = super(PageEditCellView, self).get_context_data(**kwargs) context['cell'] = self.get_object() + context['page'] = context['cell'].page return context def get_object(self, queryset=None): @@ -564,3 +564,143 @@ def menu_json(request): response = HttpResponse(content_type=content_type) response.write(json_str) return response + + +class PageListCellAddLinkView(CreateView): + template_name = 'combo/link_cell_form.html' + + def dispatch(self, request, *args, **kwargs): + try: + self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk']) + except LinkListCell.DoesNotExist: + raise Http404 + for klass in self.cell.get_link_cell_classes(): + if klass.add_as_link_code == kwargs['link_code']: + self.model = klass + break + if self.model is None: + raise Http404 + return super(PageListCellAddLinkView, self).dispatch(request, *args, **kwargs) + + def get_form_class(self): + return self.model().get_default_form_class() + + def get_form_kwargs(self): + kwargs = super(PageListCellAddLinkView, self).get_form_kwargs() + kwargs['instance'] = self.model(page=self.cell.page, placeholder=self.cell.link_placeholder) + return kwargs + + def form_valid(self, form): + orders = [x.order for x in self.cell.get_items()] + if orders: + form.instance.order = max(orders)+1 + else: + form.instance.order = 1 + return super(PageListCellAddLinkView, self).form_valid(form) + + def get_success_url(self): + return '%s#cell-%s' % ( + reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}), + self.kwargs['cell_reference']) + + +page_list_cell_add_link = PageListCellAddLinkView.as_view() + + +class PageListCellEditLinkView(UpdateView): + template_name = 'combo/link_cell_form.html' + + def dispatch(self, request, *args, **kwargs): + try: + self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk']) + except LinkListCell.DoesNotExist: + raise Http404 + try: + self.object = CellBase.get_cell(kwargs['link_cell_reference'], page=kwargs['page_pk']) + except ObjectDoesNotExist: + raise Http404 + if self.object.placeholder != self.cell.link_placeholder: + raise Http404 + self.model = self.object.__class__ + return super(PageListCellEditLinkView, self).dispatch(request, *args, **kwargs) + + def get_object(self, *args, **kwargs): + return self.object + + def get_form_class(self): + return self.model().get_default_form_class() + + def form_valid(self, form): + if self.request.is_ajax(): + self.object = form.save() + response = self.form_invalid(form) # avoid redirection + else: + response = super(PageListCellEditLinkView, self).form_valid(form) + PageSnapshot.take(self.cell.page, request=self.request, comment=_('changed cell "%s"') % self.cell) + return response + + def get_success_url(self): + return '%s#cell-%s' % ( + reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}), + self.kwargs['cell_reference']) + + +page_list_cell_edit_link = PageListCellEditLinkView.as_view() + + +class PageListCellDeleteLinkView(DeleteView): + template_name = 'combo/generic_confirm_delete.html' + + def dispatch(self, request, *args, **kwargs): + try: + self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk']) + except LinkListCell.DoesNotExist: + raise Http404 + try: + self.object = CellBase.get_cell(kwargs['link_cell_reference'], page=kwargs['page_pk']) + except ObjectDoesNotExist: + raise Http404 + if self.object.placeholder != self.cell.link_placeholder: + raise Http404 + self.model = self.object.__class__ + return super(PageListCellDeleteLinkView, self).dispatch(request, *args, **kwargs) + + def get_object(self, *args, **kwargs): + return self.object + + def delete(self, request, *args, **kwargs): + response = super(PageListCellDeleteLinkView, self).delete(request, *args, **kwargs) + PageSnapshot.take(self.cell.page, request=self.request, comment=_('changed cell "%s"') % self.cell) + return response + + def get_success_url(self): + return '%s#cell-%s' % ( + reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}), + self.kwargs['cell_reference']) + + +page_list_cell_delete_link = PageListCellDeleteLinkView.as_view() + + +def link_list_order(request, page_pk, cell_reference): + try: + cell = CellBase.get_cell(cell_reference, page=page_pk) + except LinkListCell.DoesNotExist: + raise Http404 + + has_changes = False + for link in cell.get_items(): + old_order = link.order + try: + new_order = int(request.GET.get('pos_' + str(link.pk))) + except TypeError: + continue + if new_order != old_order: + link.order = new_order + has_changes = True + link.save(update_fields=['order']) + + if has_changes: + PageSnapshot.take(cell.page, request=request, comment=_('reordered cells')) + + return HttpResponse(status=204) diff --git a/combo/public/templates/combo/link-list-cell.html b/combo/public/templates/combo/link-list-cell.html new file mode 100644 index 00000000..706d7306 --- /dev/null +++ b/combo/public/templates/combo/link-list-cell.html @@ -0,0 +1,12 @@ +{% block cell-content %} +{% spaceless %} + +{% endspaceless %} +{% endblock %} diff --git a/tests/test_cells.py b/tests/test_cells.py index 89ddb096..90683ef7 100644 --- a/tests/test_cells.py +++ b/tests/test_cells.py @@ -4,7 +4,10 @@ import os import pytest import requests -from combo.data.models import Page, CellBase, TextCell, LinkCell, MenuCell, JsonCellBase, JsonCell, ConfigJsonCell +from combo.data.models import ( + Page, CellBase, TextCell, LinkCell, MenuCell, JsonCellBase, + JsonCell, ConfigJsonCell, LinkListCell +) from django.conf import settings from django.db import connection from django.forms.widgets import Media @@ -93,6 +96,7 @@ def test_text_cell_variadic_url(): assert 'href=""' in cell.render(ctx) assert 'href="/plop"' in cell.render(ctx) + def test_link_cell(): page = Page(title='example page', slug='example-page') page.save() @@ -130,6 +134,37 @@ def test_link_cell(): assert cell.render(ctx).strip() == 'altertitle' +def test_link_list_cell(): + page = Page.objects.create(title='example page', slug='example-page') + + cell = LinkListCell.objects.create(order=0, page=page) + item = LinkCell.objects.create( + page=page, + placeholder=cell.link_placeholder, + title='Example Site', + url='http://example.net/', + order=0, + ) + + ctx = {'page_cells': [item]} + assert '' in cell.render(ctx) + + item.title = '' + assert '' in cell.render(ctx) + + item.link_page = page + assert '' in cell.render(ctx) + + item.title = 'altertitle' + assert '' in cell.render(ctx) + + item.anchor = 'anchor' + assert '' in cell.render(ctx) + + item.link_page = None + assert '' in cell.render(ctx) + + def test_menu_cell(): Page.objects.all().delete() parent = page = Page(title='Page1', slug='page1', template_name='standard') @@ -728,3 +763,27 @@ def test_related_cell_types_tracking(): TextCell(page=page, placeholder='content', order=0, text='hello').save() assert set(Page.objects.get(id=page.id).related_cells['cell_types']) == set(['data_textcell', 'data_linkcell']) + + +def test_link_list_cell_duplicate(): + page = Page.objects.create(title='xxx', slug='new', template_name='standard') + cell = LinkListCell.objects.create(order=0, page=page) + item = LinkCell.objects.create( + page=page, + placeholder=cell.link_placeholder, + title='Example Site', + url='http://example.net/', + link_page=page, + order=1, + ) + + new_cell = cell.duplicate() + assert LinkCell.objects.count() == 2 + assert len(new_cell.get_items()) == 1 + new_item = new_cell.get_items()[0] + assert new_item.page == page + assert new_item.placeholder == new_cell.link_placeholder + assert new_item.pk != item.pk + assert new_item.title == item.title + assert new_item.url == item.url + assert new_item.link_page == item.link_page diff --git a/tests/test_manager.py b/tests/test_manager.py index 0b9b7aef..58ad4db7 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -21,7 +21,7 @@ from webtest import TestApp from webtest import Upload from combo.wsgi import application -from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot +from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot, LinkListCell from combo.apps.assets.models import Asset from combo.apps.family.models import FamilyInfosCell from combo.apps.search.models import SearchCell @@ -1373,3 +1373,73 @@ def test_json_cell_syntax_validation(app, admin_user): assert 'syntax error' not in resp.text assert JsonCell.objects.count() == 1 assert JsonCell.objects.first().template_string == '{{ ok }}' + + +def test_add_edit_delete_list_link_item(app, admin_user): + Page.objects.all().delete() + page = Page.objects.create(title='One', slug='one', template_name='standard') + cell = LinkListCell.objects.create(order=0, placeholder='content', page=page) + app = login(app) + resp = app.get('/manage/pages/%s/' % page.pk) + + resp = resp.click(href='.*/add-link/link$') + resp.forms[0]['title'] = 'Hello world' + resp.forms[0]['url'] = 'http://example.com' + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert LinkCell.objects.count() == 1 + item = LinkCell.objects.get() + assert item.title == 'Hello world' + assert item.url == 'http://example.com' + assert item.page == page + assert item.placeholder == cell.link_placeholder + + resp = resp.follow() + resp = resp.click(href='.*/link/%s/$' % item.get_reference()) + resp.forms[0]['title'] = 'Hello world 2' + resp.forms[0]['url'] = 'http://example2.com' + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert LinkCell.objects.count() == 1 + item.refresh_from_db() + assert item.title == 'Hello world 2' + assert item.url == 'http://example2.com' + + resp = resp.follow() + resp = resp.click(href='.*/link/%s/delete' % item.get_reference()) + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert LinkCell.objects.count() == 0 + + +def test_edit_link_list_order(app, admin_user): + Page.objects.all().delete() + page = Page.objects.create(title='One', slug='one', template_name='standard') + cell = LinkListCell.objects.create(order=0, page=page) + items = [] + for i in range(5): + items.append( + LinkCell.objects.create( + page=page, + placeholder=cell.link_placeholder, + title='Foo %s' % i, + url='http://example.net/', + link_page=page, + order=i+1, + ) + ) + + params = [] + new_order = [2, 3, 1, 4, 5] + for i, (item, new_pos) in enumerate(zip(items, new_order)): + params.append(('pos_%s' % item.pk, str(new_pos))) + + app = login(app) + resp = app.get('/manage/pages/%s/cell/%s/order?%s' % (page.pk, cell.get_reference(), urlencode(params))) + assert resp.status_code == 204 + for i, item in enumerate(items): + item.refresh_from_db() + assert item.order == new_order[i] diff --git a/tests/test_pages.py b/tests/test_pages.py index 5f45670e..2eb108fc 100644 --- a/tests/test_pages.py +++ b/tests/test_pages.py @@ -9,7 +9,7 @@ from django.test import override_settings from django.test.client import RequestFactory from django.utils.six import StringIO from django.utils.timezone import now -from combo.data.models import Page, PageSnapshot, CellBase, TextCell, LinkCell +from combo.data.models import Page, PageSnapshot, CellBase, TextCell, LinkCell, LinkListCell from combo.data.management.commands.import_site import Command as ImportSiteCommand from combo.data.management.commands.export_site import Command as ExportSiteCommand from combo.manager.forms import PageVisibilityForm @@ -182,6 +182,22 @@ def test_import_export_pages_with_links(): cell2 = LinkCell(page=page2, title='foo', placeholder='content', link_page=page, order=1) cell2.save() + cell3 = LinkListCell.objects.create(page=page, placeholder='content', order=2) + item1 = LinkCell.objects.create( + page=page, + placeholder=cell3.link_placeholder, + title='Example Site', + url='http://example.net/', + order=0, + ) + item2 = LinkCell.objects.create( + page=page, + placeholder=cell3.link_placeholder, + title='blah', + link_page=page2, + order=1, + ) + site_export = [x.get_serialized_page() for x in Page.objects.all()] Page.objects.all().delete() @@ -189,8 +205,21 @@ def test_import_export_pages_with_links(): new_page_1 = Page.objects.all().order_by('order')[0] new_page_2 = Page.objects.all().order_by('order')[1] - assert CellBase.get_cells(page_id=new_page_1.id)[0].link_page_id == new_page_2.id - assert CellBase.get_cells(page_id=new_page_2.id)[0].link_page_id == new_page_1.id + new_cells_1 = CellBase.get_cells(page_id=new_page_1.id, placeholder='content') + new_cells_2 = CellBase.get_cells(page_id=new_page_2.id, placeholder='content') + assert new_cells_1[0].link_page_id == new_page_2.id + assert new_cells_2[0].link_page_id == new_page_1.id + assert len(new_cells_1[1].get_items()) == 2 + new_item_1 = new_cells_1[1].get_items()[0] + assert isinstance(new_item_1, LinkCell) + assert new_item_1.title == item1.title + assert new_item_1.url == item1.url + assert new_item_1.link_page is None + new_item_2 = new_cells_1[1].get_items()[1] + assert isinstance(new_item_2, LinkCell) + assert new_item_2.title == item2.title + assert new_item_2.url == '' + assert new_item_2.link_page == new_page_2 def test_duplicate_page(): diff --git a/tests/test_wcs.py b/tests/test_wcs.py index 6dabae73..f145129a 100644 --- a/tests/test_wcs.py +++ b/tests/test_wcs.py @@ -22,7 +22,7 @@ from django.utils.six.moves.urllib import parse as urlparse import mock -from combo.data.models import Page +from combo.data.models import CellBase, LinkListCell, Page from combo.apps.search.engines import engines from combo.apps.wcs.models import (WcsFormCell, WcsCurrentFormsCell, WcsFormsOfCategoryCell, WcsCurrentDraftsCell, WcsCategoryCell, @@ -901,3 +901,93 @@ def test_backoffice_submission_cell_render(context): result = cell.render(context) assert '/backoffice/submission/a-private-form/' in result + + +@wcs_present +def test_manager_link_list_cell_duplicate(): + page = Page.objects.create(title='xxx', slug='new', template_name='standard') + cell = LinkListCell.objects.create(order=0, page=page) + item = WcsFormCell.objects.create( + page=page, + placeholder=cell.link_placeholder, + cached_title='A title', + cached_url='http://example.com', + cached_json={'foo': 'bar'}, + order=1) + + new_cell = cell.duplicate() + assert WcsFormCell.objects.count() == 2 + assert len(new_cell.get_items()) == 1 + new_item = new_cell.get_items()[0] + assert new_item.page == page + assert new_item.placeholder == new_cell.link_placeholder + assert new_item.pk != item.pk + assert new_item.cached_title == item.cached_title + assert new_item.cached_url == item.cached_url + assert new_item.cached_json == item.cached_json + + +@wcs_present +def test_manager_add_edit_delete_list_link_item(app, admin_user): + Page.objects.all().delete() + page = Page.objects.create(title='One', slug='one', template_name='standard') + cell = LinkListCell.objects.create(order=0, placeholder='content', page=page) + app = login(app) + resp = app.get('/manage/pages/%s/' % page.pk) + + resp = resp.click(href='.*/add-link/form-link$') + resp.forms[0]['formdef_reference'] = 'default:form-title' + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert WcsFormCell.objects.count() == 1 + item = WcsFormCell.objects.get() + assert item.formdef_reference == 'default:form-title' + assert item.page == page + assert item.placeholder == cell.link_placeholder + + resp = resp.follow() + resp = resp.click(href='.*/link/%s/$' % item.get_reference()) + resp.forms[0]['formdef_reference'] = 'default:a-private-form' + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert WcsFormCell.objects.count() == 1 + item.refresh_from_db() + assert item.formdef_reference == 'default:a-private-form' + + resp = resp.follow() + resp = resp.click(href='.*/link/%s/delete' % item.get_reference()) + resp = resp.forms[0].submit() + assert resp.status_int == 302 + assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference())) + assert WcsFormCell.objects.count() == 0 + + +def test_import_export_pages_with_links(): + page = Page(title=u'bar', slug='bar', order=1) + page.save() + + cell = LinkListCell.objects.create(order=0, placeholder='content', page=page) + item = WcsFormCell.objects.create( + page=page, + placeholder=cell.link_placeholder, + cached_title='A title', + cached_url='http://example.com', + cached_json={'foo': 'bar'}, + order=0, + ) + + site_export = [x.get_serialized_page() for x in Page.objects.all()] + Page.objects.all().delete() + + Page.load_serialized_pages(site_export) + + new_page = Page.objects.get() + new_cells = CellBase.get_cells(page_id=new_page.id, placeholder='content') + assert len(new_cells[0].get_items()) == 1 + new_item = new_cells[0].get_items()[0] + assert isinstance(new_item, WcsFormCell) + assert new_item.cached_title == item.cached_title + assert new_item.cached_url == item.cached_url + assert new_item.cached_json == item.cached_json