From 831b9c4ba95feca65c2cfe11a0e1185933fd4b30 Mon Sep 17 00:00:00 2001
From: Nicolas Wavrant <nicolas.wavrant@nexedi.com>
Date: Thu, 29 Mar 2018 09:19:54 +0000
Subject: [PATCH] erp5_crm: Ticket_newEvent support upload of attachments on
 the Event

---
 .../erp5_crm/Base_viewCRMFieldLibrary.xml     |   1 +
 .../my_file_field.xml                         |  84 +++++++++++
 .../portal_skins/erp5_crm/Ticket_newEvent.py  |  10 ++
 .../portal_skins/erp5_crm/Ticket_newEvent.xml |   2 +-
 .../Ticket_validateAttachmentFileField.py     |  10 ++
 .../Ticket_validateAttachmentFileField.xml    |  62 ++++++++
 .../erp5_crm/Ticket_viewNewEventDialog.xml    |   3 +-
 .../your_attachment_file.xml                  | 112 +++++++++++++++
 product/ERP5/tests/testCRM.py                 | 132 ++++++++++++++++++
 9 files changed, 414 insertions(+), 2 deletions(-)
 create mode 100644 bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary/my_file_field.xml
 create mode 100644 bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.py
 create mode 100644 bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.xml
 create mode 100644 bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog/your_attachment_file.xml

diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary.xml
index 3c757855fe..62a4026447 100644
--- a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary.xml
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary.xml
@@ -156,6 +156,7 @@
                         <string>your_dialog_ticket_type</string>
                         <string>your_report_ticket_type</string>
                         <string>your_dialog_ticket_simulation_state</string>
+                        <string>my_file_field</string>
                       </list>
                     </value>
                 </item>
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary/my_file_field.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary/my_file_field.xml
new file mode 100644
index 0000000000..a13c018323
--- /dev/null
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Base_viewCRMFieldLibrary/my_file_field.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>title</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_file_field</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_file_field</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>File</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.py b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.py
index e9408b5fc1..c9eda74669 100644
--- a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.py
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.py
@@ -20,6 +20,16 @@ response = module.newContent(portal_type=portal_type,
                              follow_up_value=context,
                              content_type=content_type)
 
+if attachment_file:
+  document = response.Base_contribute(
+    batch_mode=True,
+    redirect_to_document=False,
+    use_context_for_container=True,
+    portal_type='Embedded File',
+    file=attachment_file,
+  )
+  response.setAggregateValue(document)
+
 if notification_message:
   response.Event_setTextContentFromNotificationMessage(
     reference=notification_message
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.xml
index 1da5b91245..04bcafb0ce 100644
--- a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.xml
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_newEvent.xml
@@ -50,7 +50,7 @@
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>form_id=None, portal_type=None, resource=None,  title=None, text_content=None, start_date=None, event_workflow_action=None, notification_message=None, source=None, destination=None, content_type=None, workflow_action=None, **kw</string> </value>
+            <value> <string>form_id=None, portal_type=None, resource=None,  title=None, text_content=None, start_date=None, event_workflow_action=None, notification_message=None, source=None, destination=None, attachment_file=None, content_type=None, workflow_action=None, **kw</string> </value>
         </item>
         <item>
             <key> <string>id</string> </key>
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.py b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.py
new file mode 100644
index 0000000000..c04ff2b950
--- /dev/null
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.py
@@ -0,0 +1,10 @@
+"""
+This validator prevents users to add attachments to an event
+if this event doesn't support 'Embedded Files'.
+"""
+if not editor:
+  return True
+event_type = context.getPortalObject().portal_types[request.form.get('field_your_portal_type', None)]
+if 'Embedded File' in event_type.getTypeAllowedContentTypeList():
+  return True
+return False
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.xml
new file mode 100644
index 0000000000..591cb6619b
--- /dev/null
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_validateAttachmentFileField.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string>editor, request</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Ticket_validateAttachmentFileField</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog.xml
index 1aefc2e83f..982056a940 100644
--- a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog.xml
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog.xml
@@ -53,7 +53,7 @@
         </item>
         <item>
             <key> <string>enctype</string> </key>
-            <value> <string></string> </value>
+            <value> <string>multipart/form-data</string> </value>
         </item>
         <item>
             <key> <string>group_list</string> </key>
@@ -113,6 +113,7 @@
                       <list>
                         <string>your_source</string>
                         <string>your_destination</string>
+                        <string>your_attachment_file</string>
                       </list>
                     </value>
                 </item>
diff --git a/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog/your_attachment_file.xml b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog/your_attachment_file.xml
new file mode 100644
index 0000000000..801260e353
--- /dev/null
+++ b/bt5/erp5_crm/SkinTemplateItem/portal_skins/erp5_crm/Ticket_viewNewEventDialog/your_attachment_file.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>external_validator</string>
+                <string>title</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>delegated_message_list</string> </key>
+            <value>
+              <list>
+                <string>external_validator_failed</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>your_attachment_file</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>Attachments are not allowed for this Event Type.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_file_field</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewCRMFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>Attachment</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="Method" module="Products.Formulator.MethodField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>method_name</string> </key>
+            <value> <string>Ticket_validateAttachmentFileField</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/tests/testCRM.py b/product/ERP5/tests/testCRM.py
index 857705fdc7..f37ded77da 100644
--- a/product/ERP5/tests/testCRM.py
+++ b/product/ERP5/tests/testCRM.py
@@ -1423,6 +1423,138 @@ class TestCRMMailSend(BaseTestCRM):
                      str(document.getTextContent()))
     self.assertEqual(part.get_content_type(), 'text/html')
 
+  def test_AttachPdfToMailUsingNewEventDialog(self):
+    """
+    Make sure that pdf document is correctly attached in email
+    """
+    # Add a document which will be attached.
+    # pdf
+    filename = 'sample_attachment.pdf'
+    file_object = makeFileUpload(filename)
+
+    # Add a ticket
+    ticket = self.portal.campaign_module.newContent(portal_type='Campaign',
+                                                    title='Advertisement')
+    # Create a event
+    ticket.Ticket_newEvent(portal_type='Mail Message',
+                           title='Our new product',
+                           text_content='Buy this now!',
+                           event_workflow_action='plan',
+                           attachment_file=file_object)
+
+    # Check that attachment is embedded in Mail Message
+    event, = self.portal.event_module.objectValues()
+    document, = event.objectValues(portal_type='Embedded File')
+    self.assertEqual(document.getFilename(), filename)
+
+    # Set sender to the event.
+    event.edit(source='person_module/me',
+               destination='person_module/recipient',
+               text_content='This is an advertisement mail.')
+
+    mail_text = event.send(download=True)
+
+    # Check mail text.
+    message = message_from_string(mail_text)
+    part = None
+    for i in message.get_payload():
+      if i.get_content_type()=='text/plain':
+        part = i
+    self.assertEqual(part.get_payload(decode=True), event.getTextContent())
+
+    # Check attachment
+    # pdf
+    self.assert_(filename in
+                 [i.get_filename() for i in message.get_payload()])
+    part = None
+    for i in message.get_payload():
+      if i.get_filename()==filename:
+        part = i
+    self.assertEqual(part.get_payload(decode=True), str(document.getData()))
+
+  def test_AttachFileToMailUsingNewEventDialog(self):
+    """
+    Make sure that file document is correctly attached in email
+    """
+    # Add a document which will be attached.
+    filename = 'sample_attachment.zip'
+    file_object = makeFileUpload(filename)
+
+    # Add a ticket
+    ticket = self.portal.campaign_module.newContent(portal_type='Campaign',
+                                                    title='Advertisement')
+    # Create a event
+    ticket.Ticket_newEvent(portal_type='Mail Message',
+                           title='Our new product',
+                           text_content='Buy this now!',
+                           event_workflow_action='plan',
+                           attachment_file=file_object)
+
+    # Check that attachment is embedded in Mail Message
+    event, = self.portal.event_module.objectValues()
+    document, = event.objectValues(portal_type='Embedded File')
+    self.assertEqual(document.getFilename(), filename)
+
+    # Set sender to the event.
+    event, = self.portal.event_module.objectValues()
+    event.edit(source='person_module/me',
+               destination='person_module/recipient',
+               text_content='This is an advertisement mail.')
+
+    mail_text = event.send(download=True)
+    # Check mail text.
+    message = message_from_string(mail_text)
+    part = None
+    for i in message.get_payload():
+      if i.get_content_type()=='text/plain':
+        part = i
+    self.assertEqual(part.get_payload(decode=True), event.getTextContent())
+
+    # Check attachment
+    # zip
+    self.assert_(filename in
+                 [i.get_filename() for i in message.get_payload()])
+    part = None
+    for i in message.get_payload():
+      if i.get_filename() == filename:
+        part = i
+    self.assert_(len(part.get_payload(decode=True))>0)
+
+  def test_testValidatorForAttachmentField(self):
+    """
+    If an Event Type doesn't allow Emebedded Files in its sub portal types,
+    then the dialog should tell the user that attachment can't be uploaded
+    """
+    # Add a document which will be attached.
+    filename = 'sample_attachment.zip'
+    file_object = makeFileUpload(filename)
+
+    # Add a ticket
+    ticket = self.portal.campaign_module.newContent(portal_type='Campaign',
+                                                    title='Advertisement')
+
+    # Check that hypothesis is True
+    self.assertNotIn(
+      'Embedded File',
+      self.portal.portal_types['Phone Call'].getTypeAllowedContentTypeList()
+    )
+
+    request_form = self.portal.REQUEST.form
+    request_form['field_your_portal_type'] = 'Phone Call'
+
+    self.assertFalse(
+      ticket.Ticket_validateAttachmentFileField(file_object, self.portal.REQUEST))
+
+    # Check that hypothesis is True
+    self.assertIn(
+      'Embedded File',
+      self.portal.portal_types['Mail Message'].getTypeAllowedContentTypeList()
+    )
+    request_form['field_your_portal_type'] = 'Mail Message'
+
+    self.assertTrue(
+      ticket.Ticket_validateAttachmentFileField(file_object, self.portal.REQUEST))
+
   def test_MailRespond(self):
     """
     Test we can answer an incoming event and quote it
-- 
2.30.9