From 9a5b09cf463e6560f66f64a2a8fb5c760d6a57f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Fri, 10 May 2019 11:10:13 +0200
Subject: [PATCH] backoffice: warn about data deletion when removing a field
 (#32950)

---
 tests/test_admin_pages.py | 47 +++++++++++++++++++++++++++++++++++++++
 wcs/admin/fields.py       | 12 +++++++---
 wcs/admin/forms.py        |  5 +++++
 wcs/wf/form.py            |  3 +++
 4 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py
index c8025ee65..ab81452bc 100644
--- a/tests/test_admin_pages.py
+++ b/tests/test_admin_pages.py
@@ -1075,6 +1075,7 @@ def test_form_new_field(pub):
     assert '<h3 data-field-id="1">baz</h3>' in resp.body
 
 def test_form_delete_field(pub):
+    create_superuser(pub)
     create_role()
 
     FormDef.wipe()
@@ -1090,11 +1091,52 @@ def test_form_delete_field(pub):
     assert 'Use drag and drop' in resp.body
 
     resp = resp.click(href='1/delete')
+    assert 'You are about to remove the "1st field" field.' in resp.body
+    assert 'Warning:' not in resp.body
     resp = resp.forms[0].submit()
     assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
     resp = resp.follow()
     assert len(FormDef.get(1).fields) == 0
 
+def test_form_delete_field_existing_data(pub):
+    create_superuser(pub)
+    create_role()
+
+    FormDef.wipe()
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = [
+        fields.StringField(id='1', label='1st field', type='string'),
+        fields.CommentField(id='2', label='comment field', type='comment'),
+    ]
+    formdef.store()
+
+    formdata = formdef.data_class()()
+    formdata.just_created()
+    formdata.data = {'1': 'hello'}
+    formdata.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/forms/1/')
+    resp = resp.click(href='fields/')
+    resp = resp.click(href='1/delete')
+    assert 'You are about to remove the "1st field" field.' in resp.body
+    assert 'Warning:' in resp.body
+    resp = resp.forms[0].submit()
+    assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_2'
+    resp = resp.follow()
+    assert len(FormDef.get(1).fields) == 1
+
+    # check non-data fields do not show this warning
+    resp = app.get('/backoffice/forms/1/')
+    resp = resp.click(href='fields/')
+    resp = resp.click(href='2/delete')
+    assert 'You are about to remove the "comment field" field.' in resp.body
+    assert 'Warning:' not in resp.body
+    resp = resp.forms[0].submit()
+    resp = resp.follow()
+    assert len(FormDef.get(1).fields) == 0
+ 
 def test_form_duplicate_field(pub):
     user = create_superuser(pub)
     create_role()
@@ -2553,6 +2595,11 @@ def test_workflows_edit_display_form_action(pub):
     assert 'foobar' in resp.body
     resp = resp.click('Edit')
     assert not 'in_listing' in resp.form.fields.keys()
+    resp = resp.form.submit('cancel')
+    resp = resp.follow()
+    resp = resp.click('Remove')
+    assert 'You are about to remove the "foobar" field.' in resp.body
+    assert not 'Warning:' in resp.body
 
 def test_workflows_edit_choice_action(pub):
     create_superuser(pub)
diff --git a/wcs/admin/fields.py b/wcs/admin/fields.py
index c3a5972f6..3ec6c0979 100644
--- a/wcs/admin/fields.py
+++ b/wcs/admin/fields.py
@@ -98,11 +98,18 @@ class FieldDefPage(Directory):
             setattr(self.field, f.replace('-', '_'), widget.parse())
         self.objectdef.store()
 
+    def get_deletion_extra_warning(self):
+        return _('Warning: this field data will be permanently deleted.')
 
     def delete(self):
         form = Form(enctype='multipart/form-data')
+        ellipsized_field_label = misc.ellipsize(self.field.unhtmled_label, 60)
         form.widgets.append(HtmlWidget('<p>%s</p>' % _(
-                        "You are about to remove a field.")))
+            "You are about to remove the \"%s\" field.") % ellipsized_field_label))
+        if self.field.type not in ('page', 'subtitle', 'title', 'comment'):
+            warning = self.get_deletion_extra_warning()
+            if warning:
+                form.widgets.append(HtmlWidget('<div class="warningnotice">%s</div>' % warning))
         form.add_submit('delete', _('Submit'))
         form.add_submit("cancel", _("Cancel"))
         if form.get_widget('cancel').parse():
@@ -114,8 +121,7 @@ class FieldDefPage(Directory):
             get_response().breadcrumb.append(('delete', _('Delete')))
             self.html_top(title = _('Delete Field'))
             r = TemplateIO(html=True)
-            r += htmltext('<h2>%s %s</h2>') % (_('Deleting Field:'),
-                    misc.ellipsize(self.field.unhtmled_label, 60))
+            r += htmltext('<h2>%s</h2>') % _('Deleting Field: %s') % ellipsized_field_label
             r += form.render()
             return r.getvalue()
         else:
diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py
index 051f8aea2..23f44c8e4 100644
--- a/wcs/admin/forms.py
+++ b/wcs/admin/forms.py
@@ -116,6 +116,11 @@ class FormDefUI(object):
 class FieldDefPage(FieldDefPage):
     section = 'forms'
 
+    def get_deletion_extra_warning(self):
+        if not self.objectdef.data_class().count():
+            return None
+        return _('Warning: this field data will be permanently deleted from existing forms.')
+
 
 class FieldsDirectory(FieldsDirectory):
     field_def_page_class = FieldDefPage
diff --git a/wcs/wf/form.py b/wcs/wf/form.py
index 603c6ad38..d2b063380 100644
--- a/wcs/wf/form.py
+++ b/wcs/wf/form.py
@@ -62,6 +62,9 @@ class WorkflowFormFieldDefPage(FieldDefPage):
         form.remove('in_listing')
         return form
 
+    def get_deletion_extra_warning(self):
+        return None
+
 
 class WorkflowFormFieldsDirectory(FieldsDirectory):
     section = 'workflows'
-- 
2.20.1

