0001-workflows-allow-attachments-in-emails-8274.patch
tests/test_admin_pages.py | ||
---|---|---|
1919 | 1919 |
role = create_role() |
1920 | 1920 |
Workflow.wipe() |
1921 | 1921 |
workflow = Workflow(name='foo') |
1922 |
workflow.add_status(name='baz') |
|
1922 |
st1 = workflow.add_status(name='baz')
|
|
1923 | 1923 |
workflow.store() |
1924 | 1924 | |
1925 | 1925 |
app = login(get_app(pub)) |
... | ... | |
1957 | 1957 |
resp = resp.form.submit('submit') |
1958 | 1958 |
assert 'error in template' in resp.body and 'unmatched [end]' in resp.body |
1959 | 1959 | |
1960 |
# attachments without backoffice fields: python expressions |
|
1961 |
resp = app.get(item_url) |
|
1962 |
assert "Attachments (Python expressions)" in resp.body |
|
1963 |
resp.form['attachments$element0'] = 'form_var_upload_raw' |
|
1964 |
resp = resp.form.submit('submit') |
|
1965 |
assert resp.location |
|
1966 |
resp = app.get(item_url) |
|
1967 |
assert "Attachments (Python expressions)" in resp.body |
|
1968 |
assert resp.form['attachments$element0'].value == 'form_var_upload_raw' |
|
1969 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
1970 |
assert sendmail.attachments == ['form_var_upload_raw'] |
|
1971 | ||
1972 |
# attachments with backoffice fields: select-with-other inputs |
|
1973 |
workflow = Workflow.get(workflow.id) |
|
1974 |
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow) |
|
1975 |
workflow.backoffice_fields_formdef.fields = [ |
|
1976 |
fields.FileField(id='bo1', label='bo field 1', type='file', varname='upload'), |
|
1977 |
fields.FileField(id='bo2', label='bo field 2', type='file', varname='upload2'), |
|
1978 |
fields.FileField(id='bo3', label='bo field varnameless', type='file'), |
|
1979 |
] |
|
1980 |
workflow.store() |
|
1981 |
resp = app.get(item_url) |
|
1982 |
assert "Attachments" in resp.body |
|
1983 |
assert "Attachments (Python expressions)" not in resp.body |
|
1984 |
assert resp.form['attachments$element0$choice'].value == 'form_var_upload_raw' |
|
1985 |
assert len(resp.form['attachments$element0$choice'].options) == 5 |
|
1986 |
resp.form['attachments$element1$choice'] = 'form_var_upload2_raw' |
|
1987 |
resp = resp.form.submit('submit') |
|
1988 |
assert resp.location |
|
1989 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
1990 |
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw'] |
|
1991 | ||
1992 |
resp = app.get(item_url) |
|
1993 |
resp.form['attachments$element2$choice'] = 'form_fbo3' |
|
1994 |
resp = resp.form.submit('submit') |
|
1995 |
assert resp.location |
|
1996 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
1997 |
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3'] |
|
1998 | ||
1999 |
resp = app.get(item_url) |
|
2000 |
resp.form['attachments$element3$choice'] = '__other' |
|
2001 |
resp.form['attachments$element3$other'] = '{"content":"foo", "filename":"bar.txt"}' |
|
2002 |
resp = resp.form.submit('submit') |
|
2003 |
assert resp.location |
|
2004 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
2005 |
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3', |
|
2006 |
'{"content":"foo", "filename":"bar.txt"}'] |
|
2007 | ||
2008 |
# remove some backoffice fields: varnameless fbo3 disapear |
|
2009 |
workflow = Workflow.get(workflow.id) |
|
2010 |
workflow.backoffice_fields_formdef.fields = [ |
|
2011 |
fields.FileField(id='bo2', label='bo field 2', type='file', varname='upload2'), |
|
2012 |
] |
|
2013 |
workflow.store() |
|
2014 |
resp = app.get(item_url) |
|
2015 |
resp = resp.form.submit('submit') |
|
2016 |
assert resp.location |
|
2017 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
2018 |
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', |
|
2019 |
'{"content":"foo", "filename":"bar.txt"}'] |
|
2020 |
# remove all backoffice fields |
|
2021 |
workflow = Workflow.get(workflow.id) |
|
2022 |
workflow.backoffice_fields_formdef.fields = [] |
|
2023 |
workflow.store() |
|
2024 |
resp = app.get(item_url) |
|
2025 |
assert "Attachments (Python expressions)" in resp.body |
|
2026 |
resp = resp.form.submit('submit') |
|
2027 |
assert resp.location |
|
2028 |
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0] |
|
2029 |
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', |
|
2030 |
'{"content":"foo", "filename":"bar.txt"}'] |
|
2031 | ||
1960 | 2032 |
def test_workflows_edit_sms_action(pub): |
1961 | 2033 |
create_superuser(pub) |
1962 | 2034 |
role = create_role() |
tests/test_workflows.py | ||
---|---|---|
1 | 1 |
import datetime |
2 |
import os |
|
2 | 3 |
import pytest |
3 | 4 |
import shutil |
4 | 5 |
import StringIO |
... | ... | |
765 | 766 |
assert emails.count() == 1 |
766 | 767 |
assert emails.get('foobar').get('from') == 'foobar@localhost' |
767 | 768 | |
769 | ||
770 |
def test_email_attachments(pub, emails): |
|
771 |
formdef = FormDef() |
|
772 |
formdef.name = 'baz' |
|
773 |
formdef.fields = [ |
|
774 |
FileField(id='3', label='File', type='file', varname='file'), |
|
775 |
] |
|
776 |
formdef.store() |
|
777 | ||
778 |
upload = PicklableUpload('test.jpeg', 'image/jpeg') |
|
779 |
jpg = open(os.path.join(os.path.dirname(__file__), 'image-with-gps-data.jpeg')).read() |
|
780 |
upload.receive([jpg]) |
|
781 |
formdata = formdef.data_class()() |
|
782 |
formdata.data = {'3': upload} |
|
783 |
formdata.just_created() |
|
784 |
formdata.store() |
|
785 |
pub.substitutions.feed(formdata) |
|
786 | ||
787 |
sendmail = SendmailWorkflowStatusItem() |
|
788 |
sendmail.subject = 'foobar' |
|
789 |
sendmail.body = '<p>force html</p>' |
|
790 |
sendmail.to = ['to@example.net'] |
|
791 |
sendmail.attachments = ['form_var_file_raw'] |
|
792 |
sendmail.perform(formdata) |
|
793 |
get_response().process_after_jobs() |
|
794 |
assert emails.count() == 1 |
|
795 |
assert emails.emails['foobar']['msg'].is_multipart() |
|
796 |
assert emails.emails['foobar']['msg'].get_content_subtype() == 'mixed' |
|
797 |
assert emails.emails['foobar']['msg'].get_payload()[0].get_content_type() == 'text/html' |
|
798 |
assert emails.emails['foobar']['msg'].get_payload()[1].get_content_type() == 'image/jpeg' |
|
799 | ||
800 |
# build a backoffice field |
|
801 |
Workflow.wipe() |
|
802 |
FormDef.wipe() |
|
803 |
wf = Workflow(name='email with attachments') |
|
804 |
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) |
|
805 |
wf.backoffice_fields_formdef.fields = [ |
|
806 |
FileField(id='bo1', label='bo field 1', type='file', varname='backoffice_file1'), |
|
807 |
FileField(id='bo2', label='bo field 2', type='file', varname='backoffice_file2'), |
|
808 |
] |
|
809 |
st1 = wf.add_status('Status1') |
|
810 |
wf.store() |
|
811 |
formdef = FormDef() |
|
812 |
formdef.name = 'baz' |
|
813 |
formdef.fields = [ |
|
814 |
FileField(id='1', label='File', type='file', varname='frontoffice_file'), |
|
815 |
] |
|
816 |
formdef.workflow_id = wf.id |
|
817 |
formdef.store() |
|
818 |
formdata = formdef.data_class()() |
|
819 |
formdata.data = {'1': upload} |
|
820 |
formdata.just_created() |
|
821 |
formdata.store() |
|
822 |
pub.substitutions.feed(formdata) |
|
823 |
# store file in backoffice field form_fbo1 / form_var_backoffice_file_raw |
|
824 |
setbo = SetBackofficeFieldsWorkflowStatusItem() |
|
825 |
setbo.parent = st1 |
|
826 |
setbo.fields = [{'field_id': 'bo1', 'value': '=form_var_frontoffice_file_raw'}] |
|
827 |
setbo.perform(formdata) |
|
828 | ||
829 |
emails.empty() |
|
830 |
sendmail.attachments = ['form_fbo1'] |
|
831 |
sendmail.perform(formdata) |
|
832 |
get_response().process_after_jobs() |
|
833 |
assert emails.count() == 1 |
|
834 |
assert emails.emails['foobar']['msg'].is_multipart() |
|
835 |
assert emails.emails['foobar']['msg'].get_content_subtype() == 'mixed' |
|
836 |
assert emails.emails['foobar']['msg'].get_payload()[0].get_content_type() == 'text/html' |
|
837 |
assert emails.emails['foobar']['msg'].get_payload()[1].get_content_type() == 'image/jpeg' |
|
838 | ||
839 |
emails.empty() |
|
840 |
sendmail.attachments = ['form_var_backoffice_file1_raw'] |
|
841 |
sendmail.perform(formdata) |
|
842 |
get_response().process_after_jobs() |
|
843 |
assert emails.count() == 1 |
|
844 |
assert emails.emails['foobar']['msg'].is_multipart() |
|
845 |
assert emails.emails['foobar']['msg'].get_content_subtype() == 'mixed' |
|
846 |
assert emails.emails['foobar']['msg'].get_payload()[0].get_content_type() == 'text/html' |
|
847 |
assert emails.emails['foobar']['msg'].get_payload()[1].get_content_type() == 'image/jpeg' |
|
848 | ||
849 |
emails.empty() |
|
850 |
sendmail.attachments = ['form_var_backoffice_file1_raw', 'form_var_backoffice_file2_raw'] |
|
851 |
sendmail.perform(formdata) |
|
852 |
get_response().process_after_jobs() |
|
853 |
assert emails.count() == 1 |
|
854 |
assert emails.emails['foobar']['msg'].is_multipart() |
|
855 |
assert emails.emails['foobar']['msg'].get_content_subtype() == 'mixed' |
|
856 |
assert emails.emails['foobar']['msg'].get_payload()[0].get_content_type() == 'text/html' |
|
857 |
assert emails.emails['foobar']['msg'].get_payload()[1].get_content_type() == 'image/jpeg' |
|
858 |
# backoffice_file2 is unset, no more parts : |
|
859 |
assert len(emails.emails['foobar']['msg'].get_payload()) == 2 |
|
860 | ||
861 |
# set backoffice_file2 and retry |
|
862 |
setbo.fields = [{'field_id': 'bo2', |
|
863 |
'value': '={"content": "blah", "filename": "hello.txt", ' |
|
864 |
'"content_type": "text/plain"}'}] |
|
865 |
setbo.perform(formdata) |
|
866 |
emails.empty() |
|
867 |
sendmail.perform(formdata) |
|
868 |
get_response().process_after_jobs() |
|
869 |
assert emails.count() == 1 |
|
870 |
assert emails.emails['foobar']['msg'].is_multipart() |
|
871 |
assert emails.emails['foobar']['msg'].get_content_subtype() == 'mixed' |
|
872 |
assert emails.emails['foobar']['msg'].get_payload()[0].get_content_type() == 'text/html' |
|
873 |
assert emails.emails['foobar']['msg'].get_payload()[1].get_content_type() == 'image/jpeg' |
|
874 |
assert emails.emails['foobar']['msg'].get_payload()[2].get_content_type() == 'text/plain' |
|
875 |
assert emails.emails['foobar']['msg'].get_payload()[2].get_payload() == 'blah' |
|
876 |
assert len(emails.emails['foobar']['msg'].get_payload()) == 3 |
|
877 | ||
878 | ||
768 | 879 |
def test_webservice_call(pub): |
769 | 880 |
pub.substitutions.feed(MockSubstitutionVariables()) |
770 | 881 |
wcs/workflows.py | ||
---|---|---|
38 | 38 |
import qommon.errors |
39 | 39 | |
40 | 40 |
from wcs.roles import Role, logged_users_role, get_user_roles |
41 |
from wcs.fields import FileField |
|
41 | 42 |
from wcs.formdef import FormDef |
42 | 43 |
from wcs.formdata import Evolution |
43 | 44 | |
... | ... | |
2015 | 2016 |
subject = None |
2016 | 2017 |
body = None |
2017 | 2018 |
custom_from = None |
2019 |
attachments = None |
|
2018 | 2020 | |
2019 | 2021 |
comment = None |
2020 | 2022 | |
... | ... | |
2053 | 2055 |
return _('Send mail (not completed)') |
2054 | 2056 | |
2055 | 2057 |
def get_parameters(self): |
2056 |
return ('to', 'subject', 'body', 'custom_from') |
|
2058 |
return ('to', 'subject', 'body', 'attachments', 'custom_from')
|
|
2057 | 2059 | |
2058 | 2060 |
def fill_admin_form(self, form): |
2059 | 2061 |
self.add_parameters_widgets(form, self.get_parameters()) |
2060 | 2062 | |
2063 |
def get_attachments_options(self): |
|
2064 |
attachments_options = [(None, '---', None)] |
|
2065 |
varnameless = [] |
|
2066 |
for field in self.parent.parent.get_backoffice_fields(): |
|
2067 |
if field.key != 'file': |
|
2068 |
continue |
|
2069 |
if field.varname: |
|
2070 |
codename = 'form_var_%s_raw' % field.varname |
|
2071 |
else: |
|
2072 |
codename = 'form_f%s' % field.id # = form_fbo<n> |
|
2073 |
varnameless.append(codename) |
|
2074 |
attachments_options.append((codename, field.label, codename)) |
|
2075 |
# filter: do not consider removed fields without varname |
|
2076 |
attachments = [attachment for attachment in self.attachments or [] |
|
2077 |
if ((not attachment.startswith('form_fbo')) or |
|
2078 |
(attachment in varnameless))] |
|
2079 |
return attachments_options, attachments |
|
2080 | ||
2061 | 2081 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): |
2062 | 2082 |
if 'to' in parameters: |
2063 | 2083 |
form.add(WidgetList, '%sto' % prefix, title=_('To'), |
... | ... | |
2076 | 2096 |
value=self.body, cols=80, rows=10, |
2077 | 2097 |
validation_function=ComputedExpressionWidget.validate_ezt, |
2078 | 2098 |
hint=_('Available variables: url, url_status, details, name, number, comment, field_NAME')) |
2099 | ||
2100 |
if 'attachments' in parameters: |
|
2101 |
attachments_options, attachments = self.get_attachments_options() |
|
2102 |
if len(attachments_options) > 1: |
|
2103 |
form.add(WidgetList, '%sattachments' % prefix, title=_('Attachments'), |
|
2104 |
element_type=SingleSelectWidgetWithOther, |
|
2105 |
value=attachments, |
|
2106 |
add_element_label=_('Add attachment'), |
|
2107 |
element_kwargs={'render_br': False, 'options': attachments_options}) |
|
2108 |
else: |
|
2109 |
form.add(WidgetList, '%sattachments' % prefix, |
|
2110 |
title=_('Attachments (Python expressions)'), |
|
2111 |
element_type=StringWidget, |
|
2112 |
value=attachments, |
|
2113 |
add_element_label=_('Add attachment'), |
|
2114 |
element_kwargs={'render_br': False, 'size': 50}, |
|
2115 |
advanced=not(bool(attachments))) |
|
2116 | ||
2079 | 2117 |
if 'custom_from' in parameters: |
2080 | 2118 |
form.add(ComputedExpressionWidget, '%scustom_from' % prefix, |
2081 | 2119 |
title=_('Custom From Address'), value=self.custom_from, |
... | ... | |
2152 | 2190 |
if self.custom_from: |
2153 | 2191 |
email_from = self.compute(self.custom_from) |
2154 | 2192 | |
2193 |
attachments = [] |
|
2194 |
if self.attachments: |
|
2195 |
global_eval_dict = get_publisher().get_global_eval_dict() |
|
2196 |
local_eval_dict = get_publisher().substitutions.get_context_variables() |
|
2197 |
for attachment in self.attachments: |
|
2198 |
try: |
|
2199 |
picklableupload = eval(attachment, global_eval_dict, local_eval_dict) |
|
2200 |
except: |
|
2201 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
2202 |
context='[Sendmail/attachments]') |
|
2203 |
continue |
|
2204 |
if picklableupload: |
|
2205 |
try: |
|
2206 |
picklableupload = FileField.convert_value_from_anything(picklableupload) |
|
2207 |
except ValueError: |
|
2208 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
2209 |
context='[Sendmail/attachments]') |
|
2210 |
continue |
|
2211 |
attachments.append(picklableupload) |
|
2212 | ||
2155 | 2213 |
if len(addresses) > 1: |
2156 | 2214 |
emails.email(mail_subject, mail_body, email_rcpt=None, |
2157 | 2215 |
bcc=addresses, email_from=email_from, |
2158 | 2216 |
exclude_current_user=False, |
2217 |
attachments=attachments, |
|
2159 | 2218 |
fire_and_forget=True) |
2160 | 2219 |
else: |
2161 | 2220 |
emails.email(mail_subject, mail_body, email_rcpt=addresses, |
2162 | 2221 |
email_from=email_from, exclude_current_user=False, |
2222 |
attachments=attachments, |
|
2163 | 2223 |
fire_and_forget=True) |
2164 | 2224 |
register_item_class(SendmailWorkflowStatusItem) |
2165 | 2225 | |
2166 |
- |