From c8dd908a5b8764e4e01459342522fe5c1626428e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 26 Feb 2021 10:13:23 +0100
Subject: [PATCH 1/2] manager: duplicate cell (#51075)

---
 combo/data/models.py                          |  8 ++++++-
 .../combo/manager_edit_cell_block.html        |  1 +
 combo/manager/urls.py                         |  5 ++++
 combo/manager/views.py                        | 17 +++++++++++++
 tests/test_manager.py                         | 24 ++++++++++++++++---
 5 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/combo/data/models.py b/combo/data/models.py
index 1059b237..1f1af3d5 100644
--- a/combo/data/models.py
+++ b/combo/data/models.py
@@ -1099,7 +1099,7 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
     def import_subobjects(self, cell_json):
         pass
 
-    def duplicate(self, page_target=None, placeholder=None):
+    def duplicate(self, page_target=None, placeholder=None, reset_slug=False, set_order=False):
         # clone current cell
         new_cell = copy.deepcopy(self)
         new_cell.pk = None
@@ -1107,6 +1107,12 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
         new_cell.page = page_target or self.page
         # set placeholder
         new_cell.placeholder = placeholder or new_cell.placeholder
+        # reset slug if requested
+        if reset_slug:
+            new_cell.slug = ''
+        # set order if requested
+        if set_order:
+            new_cell.order = self.order + 1
         # store new cell
         new_cell.save()
 
diff --git a/combo/manager/templates/combo/manager_edit_cell_block.html b/combo/manager/templates/combo/manager_edit_cell_block.html
index cc48a5b7..d521bd89 100644
--- a/combo/manager/templates/combo/manager_edit_cell_block.html
+++ b/combo/manager/templates/combo/manager_edit_cell_block.html
@@ -18,6 +18,7 @@
 <a rel="popup" href="{% url 'combo-manager-page-visibility-cell' page_pk=page.id cell_reference=cell.get_reference %}">{% trans 'Visibility' %}</a> |
 <a rel="popup" href="{% url 'combo-manager-page-options-cell' page_pk=page.id cell_reference=cell.get_reference %}">{% trans 'Options' %}</a> |
 {% if cell.can_have_assets %}<a rel="popup" data-selector="div#assets-listing" href="{% url 'combo-manager-slot-assets' cell_reference=cell.get_reference %}">{% trans 'Assets' %}</a> |{% endif %}
+<a href="{% url 'combo-manager-page-duplicate-cell' page_pk=page.id cell_reference=cell.get_reference %}">{% trans 'Duplicate' %}</a> |
 <a class="close-button" href="#">{% trans 'Close' %}</a>
 {% if form %}
 <button class="save submit-button">{% trans 'Save' %}</button>
diff --git a/combo/manager/urls.py b/combo/manager/urls.py
index 5dc53db3..8488d2c9 100644
--- a/combo/manager/urls.py
+++ b/combo/manager/urls.py
@@ -84,6 +84,11 @@ urlpatterns = [
         views.page_delete_cell,
         name='combo-manager-page-delete-cell',
     ),
+    url(
+        r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/duplicate$',
+        views.page_duplicate_cell,
+        name='combo-manager-page-duplicate-cell',
+    ),
     url(
         r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/options$',
         views.page_cell_options,
diff --git a/combo/manager/views.py b/combo/manager/views.py
index 51ec2af6..133162cf 100644
--- a/combo/manager/views.py
+++ b/combo/manager/views.py
@@ -623,6 +623,23 @@ class PageDeleteCellView(DeleteView):
 page_delete_cell = PageDeleteCellView.as_view()
 
 
+class PageDuplicateCellView(RedirectView):
+    permanent = False
+
+    def get_redirect_url(self, page_pk, cell_reference):
+        try:
+            cell = CellBase.get_cell(cell_reference, page_id=page_pk)
+        except ObjectDoesNotExist:
+            raise Http404()
+        cell.duplicate(reset_slug=True, set_order=True)
+        PageSnapshot.take(cell.page, request=self.request, comment=_('duplicated cell "%s"') % cell)
+        messages.info(self.request, _('Cell %s has been duplicated.') % cell)
+        return reverse('combo-manager-page-view', kwargs={'pk': page_pk}) + '#cell-' + cell.get_reference()
+
+
+page_duplicate_cell = PageDuplicateCellView.as_view()
+
+
 class PageCellVisibilityView(PageEditCellView):
     template_name = 'combo/cell_visibility.html'
 
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 49ab96e2..668d6faa 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -1061,7 +1061,7 @@ def test_duplicate_page(app, admin_user):
 
     app = login(app)
     resp = app.get('/manage/pages/%s/' % page.pk)
-    resp = resp.click('Duplicate')
+    resp = resp.click(href='/%s/duplicate' % page.pk)
     resp = resp.form.submit()
     new_page = Page.objects.latest('pk')
     assert resp.status_int == 302
@@ -1076,7 +1076,7 @@ def test_duplicate_page(app, admin_user):
     page.exclude_from_navigation = True
     page.save()
     resp = app.get('/manage/pages/%s/' % page.pk)
-    resp = resp.click('Duplicate')
+    resp = resp.click(href='/%s/duplicate' % page.pk)
     resp = resp.form.submit()
     new_page = Page.objects.latest('pk')
     assert resp.status_int == 302
@@ -1086,7 +1086,7 @@ def test_duplicate_page(app, admin_user):
     assert new_page.exclude_from_navigation is True
 
     resp = app.get('/manage/pages/%s/' % page.pk)
-    resp = resp.click('Duplicate')
+    resp = resp.click(href='/%s/duplicate' % page.pk)
     resp.form['title'] = 'Two'
     resp = resp.form.submit()
     new_page = Page.objects.latest('pk')
@@ -1202,6 +1202,24 @@ def test_delete_cell(app, admin_user):
     assert TextCell.objects.count() == 0
 
 
+def test_duplicate_cell(app, admin_user):
+    page = Page.objects.create(
+        title='One', slug='one', template_name='standard', exclude_from_navigation=False
+    )
+    cell = TextCell.objects.create(page=page, placeholder='content', text='Foobar', order=0, slug='foobar')
+    app = login(app)
+    resp = app.get('/manage/pages/%s/' % page.pk)
+    resp = resp.click(href='/data_textcell-%s/duplicate' % cell.pk).follow()
+    assert 'Cell %s has been duplicated.' % cell in resp.text
+    assert TextCell.objects.count() == 2
+    new_cell = TextCell.objects.latest('pk')
+    assert new_cell.slug == ''
+    assert new_cell.order == 1
+    assert new_cell.page == page
+    assert new_cell.placeholder == 'content'
+    assert PageSnapshot.objects.all().count() == 1
+
+
 def test_edit_cell_visibility(app, admin_user):
     Page.objects.all().delete()
     page = Page(title='One', slug='one', template_name='standard')
-- 
2.30.0

