From 2b9106c71e03d10f277f92cbfa7a8a3ef4a24c81 Mon Sep 17 00:00:00 2001
From: Thomas NOEL <tnoel@entrouvert.com>
Date: Thu, 24 Jan 2019 16:47:24 +0100
Subject: [PATCH] workflows: add required attribute on comment action (#30023)

---
 tests/test_backoffice_pages.py | 49 ++++++++++++++++++++++++++++++++++
 tests/test_workflow_import.py  | 13 +++++++++
 wcs/workflows.py               |  9 +++++--
 3 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py
index 43ee5c0c..d37ef2b3 100644
--- a/tests/test_backoffice_pages.py
+++ b/tests/test_backoffice_pages.py
@@ -4390,3 +4390,52 @@ def test_workflow_inspect_page(pub):
     workflow.store()
     resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
     assert '23 hours' in resp.body
+
+def test_workflow_comment_required(pub):
+    user = create_user(pub)
+    create_environment(pub)
+
+    wf = Workflow(name='blah')
+    st1 = wf.add_status('Comment')
+    st1.id = 'comment'
+    commentable = CommentableWorkflowStatusItem()
+    commentable.id = '_commentable'
+    commentable.by = ['_submitter', '_receiver']
+    st1.items.append(commentable)
+    commentable.parent = st1
+    wf.store()
+
+    formdef = FormDef.get_by_urlname('form-title')
+    formdef.data_class().wipe()
+    formdef.workflow = wf
+    formdef.store()
+
+    formdata = formdef.data_class()()
+    formdata.data = {}
+    formdata.just_created()
+    formdata.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
+    assert 'widget-required' not in resp.body
+    resp.form['comment'] = 'HELLO WORLD 1'
+    resp = resp.form.submit('button_commentable')
+    resp = resp.follow()
+    assert 'HELLO WORLD 1' in resp.body
+    assert 'widget-required' not in resp.body
+    resp.form['comment'] = None
+    resp = resp.form.submit('button_commentable')
+    resp = resp.follow()
+
+    commentable.required = True
+    wf.store()
+    resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
+    assert 'widget-required' in resp.body
+    resp.form['comment'] = '  '  # spaces == empty
+    resp = resp.form.submit('button_commentable')
+    assert 'widget-with-error' in resp.body
+    resp.form['comment'] = 'HELLO WORLD 2'
+    resp = resp.form.submit('button_commentable')
+    resp = resp.follow()
+    assert 'widget-with-error' not in resp.body
+    assert 'HELLO WORLD 2' in resp.body
diff --git a/tests/test_workflow_import.py b/tests/test_workflow_import.py
index 8019f0af..eec4e3a1 100644
--- a/tests/test_workflow_import.py
+++ b/tests/test_workflow_import.py
@@ -355,6 +355,19 @@ def test_commentable_action(pub):
 
     wf2 = assert_import_export_works(wf)
     assert wf2.possible_status[0].items[0].button_label is None
+    assert wf2.possible_status[0].items[0].required is False
+
+    commentable.required = True
+    wf2 = assert_import_export_works(wf)
+    assert wf2.possible_status[0].items[0].required is True
+
+    # import legacy comment without required attribute
+    xml_export = ET.tostring(export_to_indented_xml(wf))
+    assert '<required>True</required>' in xml_export
+    xml_export = xml_export.replace('<required>True</required>', '')
+    assert '<required>True</required>' not in xml_export
+    wf2 = Workflow.import_from_xml_tree(ET.parse(StringIO.StringIO(xml_export)))
+    assert wf2.possible_status[0].items[0].required is False
 
 
 def test_variables_formdef(pub):
diff --git a/wcs/workflows.py b/wcs/workflows.py
index 2acb4f1a..f4a08fd6 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -1943,6 +1943,7 @@ class CommentableWorkflowStatusItem(WorkflowStatusItem):
     waitpoint = True
     ok_in_global_action = False
 
+    required = False
     varname = None
     label = None
     button_label = 0 # hack to handle legacy commentable items
@@ -1962,7 +1963,7 @@ class CommentableWorkflowStatusItem(WorkflowStatusItem):
                 title = _('Comment')
             else:
                 title = self.label
-            form.add(TextWidget, 'comment', title=title, required=False,
+            form.add(TextWidget, 'comment', title=title, required=self.required,
                     cols=40, rows=10, hint=self.hint)
             form.get_widget('comment').attrs['class'] = 'comment'
             if self.button_label == 0:
@@ -1992,7 +1993,7 @@ class CommentableWorkflowStatusItem(WorkflowStatusItem):
 
     def get_parameters(self):
         return ('label', 'button_label', 'hint', 'by', 'varname',
-                'backoffice_info_text', 'condition')
+                'backoffice_info_text', 'required', 'condition')
 
     def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
         super(CommentableWorkflowStatusItem, self).add_parameters_widgets(
@@ -2020,6 +2021,10 @@ class CommentableWorkflowStatusItem(WorkflowStatusItem):
             form.add(VarnameWidget, '%svarname' % prefix,
                      title=_('Identifier'), value=self.varname,
                      hint=_('This will make the comment available in a variable named comment_ + identifier.'))
+        if 'required' in parameters:
+            form.add(CheckboxWidget, '%srequired' % prefix,
+                     title=_('Required'), value=self.required)
+
         if 'backoffice_info_text' in parameters:
             form.add(WysiwygTextWidget, '%sbackoffice_info_text' % prefix,
                      title=_('Information Text for Backoffice'),
-- 
2.20.1

