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