0001-workflow-added-attachments-for-RegisterComment.patch
tests/test_misc.py | ||
---|---|---|
440 | 440 |
assert not '<ul' in html |
441 | 441 |
assert 'arabic simple' in html |
442 | 442 |
assert 'M. Francis Kuntz' in html |
443 | ||
444 |
def test_attachment(): |
|
445 |
hello_word_b64 = base64.encodestring('hello world') |
|
446 | ||
447 |
d = evalutils.attachment(varname='var1') |
|
448 |
assert d == {'varname' : 'var1' |
|
449 |
,'filename' : '' |
|
450 |
,'content_type': 'application/octet-stream' |
|
451 |
,'b64_content' : ''} |
|
452 | ||
453 |
d = evalutils.attachment(varname ='var1' |
|
454 |
,filename='hello.txt') |
|
455 |
assert d == {'varname' : 'var1' |
|
456 |
,'filename' : 'hello.txt' |
|
457 |
,'content_type': 'application/octet-stream' |
|
458 |
,'b64_content' : ''} |
|
459 | ||
460 |
d = evalutils.attachment(varname ='var1' |
|
461 |
,content_type='text/plain') |
|
462 |
assert d == {'varname' : 'var1' |
|
463 |
,'filename' : '' |
|
464 |
,'content_type': 'text/plain' |
|
465 |
,'b64_content' : ''} |
|
466 | ||
467 |
d = evalutils.attachment(varname='var1' |
|
468 |
,content='hello world') |
|
469 |
assert d == {'varname' : 'var1' |
|
470 |
,'filename' : '' |
|
471 |
,'content_type': 'application/octet-stream' |
|
472 |
,'b64_content' : hello_word_b64} |
|
473 | ||
474 |
d = evalutils.attachment(varname ='var1' |
|
475 |
,b64_content=hello_word_b64) |
|
476 |
assert d == {'varname' : 'var1' |
|
477 |
,'filename' : '' |
|
478 |
,'content_type': 'application/octet-stream' |
|
479 |
,'b64_content' : hello_word_b64} |
|
480 | ||
481 |
d = evalutils.attachment(varname ='var1' |
|
482 |
,filename ='hello.txt' |
|
483 |
,content_type='text/plain' |
|
484 |
,content ='hello world') |
|
485 |
assert d == {'varname' : 'var1' |
|
486 |
,'filename' : 'hello.txt' |
|
487 |
,'content_type': 'text/plain' |
|
488 |
,'b64_content' : hello_word_b64} |
|
489 | ||
490 |
d = evalutils.attachment(varname ='var1' |
|
491 |
,filename ='hello.txt' |
|
492 |
,content_type='text/plain' |
|
493 |
,b64_content =hello_word_b64) |
|
494 |
assert d == {'varname' : 'var1' |
|
495 |
,'filename' : 'hello.txt' |
|
496 |
,'content_type': 'text/plain' |
|
497 |
,'b64_content' : hello_word_b64} |
|
498 | ||
499 |
d = evalutils.attachment(varname ='var1' |
|
500 |
,filename ='hello.txt' |
|
501 |
,content_type='text/plain' |
|
502 |
,content ='hello world' |
|
503 |
,b64_content =hello_word_b64) |
|
504 |
assert d == {'varname' : 'var1' |
|
505 |
,'filename' : 'hello.txt' |
|
506 |
,'content_type': 'text/plain' |
|
507 |
,'b64_content' : hello_word_b64} |
tests/test_workflows.py | ||
---|---|---|
37 | 37 |
from wcs.wf.jump import JumpWorkflowStatusItem, _apply_timeouts |
38 | 38 |
from wcs.wf.timeout_jump import TimeoutWorkflowStatusItem |
39 | 39 |
from wcs.wf.profile import UpdateUserProfileStatusItem |
40 |
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem |
|
40 |
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem, JournalEvolutionPart
|
|
41 | 41 |
from wcs.wf.remove import RemoveWorkflowStatusItem |
42 | 42 |
from wcs.wf.roles import AddRoleWorkflowStatusItem, RemoveRoleWorkflowStatusItem |
43 | 43 |
from wcs.wf.wscall import WebserviceCallStatusItem |
... | ... | |
851 | 851 |
formdata.evolution[-1]._display_parts = None |
852 | 852 |
assert formdata.evolution[-1].display_parts()[-1] == '<div><p>hello</p></div>' |
853 | 853 | |
854 |
def test_register_comment_attachment(pub): |
|
854 |
def test_register_comment_attachment_substitution(pub):
|
|
855 | 855 |
pub.substitutions.feed(MockSubstitutionVariables()) |
856 | 856 | |
857 | 857 |
formdef = FormDef() |
... | ... | |
922 | 922 |
assert url3 == url4 |
923 | 923 | |
924 | 924 | |
925 |
def test_register_comment_attachment(pub): |
|
926 |
wf = Workflow(name='comment with attachments') |
|
927 |
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) |
|
928 |
wf.backoffice_fields_formdef.fields = [ |
|
929 |
FileField(id='bo1', label='bo field 1', type='file', varname='backoffice_file1'), |
|
930 |
] |
|
931 |
st1 = wf.add_status('Status1') |
|
932 |
wf.store() |
|
933 | ||
934 |
upload = PicklableUpload('test.jpeg', 'image/jpeg') |
|
935 |
jpg = open(os.path.join(os.path.dirname(__file__), 'image-with-gps-data.jpeg')).read() |
|
936 |
upload.receive([jpg]) |
|
937 | ||
938 |
formdef = FormDef() |
|
939 |
formdef.name = 'baz' |
|
940 |
formdef.fields = [ |
|
941 |
FileField(id='1', label='File', type='file', varname='frontoffice_file'), |
|
942 |
] |
|
943 |
formdef.workflow_id = wf.id |
|
944 |
formdef.store() |
|
945 | ||
946 |
formdata = formdef.data_class()() |
|
947 |
formdata.data = {'1': upload} |
|
948 |
formdata.just_created() |
|
949 |
formdata.store() |
|
950 | ||
951 |
pub.substitutions.feed(formdata) |
|
952 | ||
953 |
setbo = SetBackofficeFieldsWorkflowStatusItem() |
|
954 |
setbo.parent = st1 |
|
955 |
setbo.fields = [{'field_id': 'bo1', 'value': '=form_var_frontoffice_file_raw'}] |
|
956 |
setbo.perform(formdata) |
|
957 | ||
958 |
if os.path.exists(os.path.join(get_publisher().app_dir, 'attachments')): |
|
959 |
shutil.rmtree(os.path.join(get_publisher().app_dir, 'attachments')) |
|
960 | ||
961 |
item = RegisterCommenterWorkflowStatusItem() |
|
962 |
item.attachments = ['form_var_backoffice_file1_raw'] |
|
963 |
item.comment = '<div>{{ attachments.%s.url }}</div>' % 'backoffice_file1' |
|
964 |
item.perform(formdata) |
|
965 | ||
966 |
assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments'))) == 1 |
|
967 |
for subdir in os.listdir(os.path.join(get_publisher().app_dir, 'attachments')): |
|
968 |
assert len(subdir) == 4 |
|
969 |
assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments', subdir))) == 1 |
|
970 | ||
971 |
assert len(formdata.evolution[-1].parts) == 2 |
|
972 |
assert isinstance(formdata.evolution[-1].parts[0], AttachmentEvolutionPart) |
|
973 |
assert formdata.evolution[-1].parts[0].varname == 'backoffice_file1' |
|
974 |
assert formdata.evolution[-1].parts[0].orig_filename == upload.orig_filename |
|
975 | ||
976 |
assert isinstance(formdata.evolution[-1].parts[1], JournalEvolutionPart) |
|
977 |
assert len(formdata.evolution[-1].parts[1].content) > 0 |
|
978 |
comment_view = str(formdata.evolution[-1].parts[1].view()) |
|
979 |
assert len(comment_view) > len('<div></div>') |
|
980 |
assert re.search('<div>[^<]+</div>', comment_view) |
|
981 | ||
982 |
if os.path.exists(os.path.join(get_publisher().app_dir, 'attachments')): |
|
983 |
shutil.rmtree(os.path.join(get_publisher().app_dir, 'attachments')) |
|
984 | ||
985 |
formdata.evolution[-1].parts = [] |
|
986 |
formdata.store() |
|
987 | ||
988 |
ws_response_varname = 'ws_response_afile' |
|
989 |
wf_data = {'%s_filename' % ws_response_varname : 'hello.txt' |
|
990 |
,'%s_content_type' % ws_response_varname : 'text/plain' |
|
991 |
,'%s_b64_content' % ws_response_varname : base64.encodestring('hello world')} |
|
992 |
formdata.update_workflow_data(wf_data) |
|
993 |
formdata.store() |
|
994 |
assert hasattr(formdata, 'workflow_data') |
|
995 |
assert isinstance(formdata.workflow_data, dict) |
|
996 | ||
997 |
item = RegisterCommenterWorkflowStatusItem() |
|
998 |
item.attachments = ["utils.attachment(varname='{0}'" |
|
999 |
",filename={1}_filename" |
|
1000 |
",b64_content ={1}_b64_content" |
|
1001 |
",content_type={1}_content_type)" |
|
1002 |
"".format('afile', ws_response_varname)] |
|
1003 |
item.comment = '{{ attachments.%s.url }}' % 'afile' |
|
1004 |
item.perform(formdata) |
|
1005 | ||
1006 |
assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments'))) == 1 |
|
1007 |
for subdir in os.listdir(os.path.join(get_publisher().app_dir, 'attachments')): |
|
1008 |
assert len(subdir) == 4 |
|
1009 |
assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments', subdir))) == 1 |
|
1010 | ||
1011 |
assert len(formdata.evolution[-1].parts) == 2 |
|
1012 |
assert isinstance(formdata.evolution[-1].parts[0], AttachmentEvolutionPart) |
|
1013 |
assert formdata.evolution[-1].parts[0].varname == 'afile' |
|
1014 |
assert formdata.evolution[-1].parts[0].orig_filename == 'hello.txt' |
|
1015 | ||
1016 |
assert isinstance(formdata.evolution[-1].parts[1], JournalEvolutionPart) |
|
1017 |
assert len(formdata.evolution[-1].parts[1].content) > 0 |
|
1018 |
comment_view = str(formdata.evolution[-1].parts[1].view()) |
|
1019 |
assert len(comment_view) > len('<div></div>') |
|
1020 |
assert re.search('<div>[^<]+</div>', comment_view) |
|
1021 | ||
1022 | ||
925 | 1023 |
def test_email(pub, emails): |
926 | 1024 |
pub.substitutions.feed(MockSubstitutionVariables()) |
927 | 1025 |
wcs/qommon/evalutils.py | ||
---|---|---|
127 | 127 |
return make_date(date) + datetime.timedelta(days=count) |
128 | 128 | |
129 | 129 | |
130 |
def attachment(content, filename='', content_type='application/octet-stream'):
|
|
130 |
def attachment(content='', filename='', content_type='application/octet-stream', b64_content='', varname=None):
|
|
131 | 131 |
'''Serialize content as an attachment''' |
132 | 132 |
import base64 |
133 | 133 | |
134 |
return {
|
|
135 |
'filename': filename,
|
|
136 |
'content_type': content_type, |
|
137 |
'b64_content': base64.b64encode(content),
|
|
134 |
d = {
|
|
135 |
'filename' : filename if filename else '',
|
|
136 |
'content_type': content_type if content_type else 'application/octet-stream',
|
|
137 |
'b64_content' : b64_content if b64_content else base64.encodestring(content)
|
|
138 | 138 |
} |
139 |
if varname: |
|
140 |
d['varname'] = varname |
|
141 |
return d |
wcs/wf/register_comment.py | ||
---|---|---|
23 | 23 | |
24 | 24 |
from wcs.workflows import WorkflowStatusItem, register_item_class, template_on_formdata |
25 | 25 | |
26 | ||
27 | 26 |
class JournalEvolutionPart: #pylint: disable=C1001 |
28 | 27 |
content = None |
29 | 28 | |
... | ... | |
84 | 83 |
value=self.comment, cols=80, rows=10) |
85 | 84 | |
86 | 85 |
def get_parameters(self): |
87 |
return ('comment', 'condition') |
|
86 |
return ('comment', 'attachments', 'condition')
|
|
88 | 87 | |
89 | 88 |
def perform(self, formdata): |
90 | 89 |
if not formdata.evolution: |
91 | 90 |
return |
91 | ||
92 |
# process attachments first, they might be used in the comment |
|
93 |
# (with substitution vars) |
|
94 |
if self.attachments: |
|
95 |
uploads = self.convert_attachments_to_uploads() |
|
96 |
self.attach_uploads_to_formdata(formdata, uploads) |
|
97 |
formdata.store() # store and invalidate cache, so references can be used in the comment message. |
|
98 | ||
99 |
# the comment can use attachments done above |
|
92 | 100 |
try: |
93 | 101 |
formdata.evolution[-1].add_part(JournalEvolutionPart(formdata, self.comment)) |
94 | 102 |
formdata.store() |
wcs/workflows.py | ||
---|---|---|
45 | 45 |
from wcs.formdef import FormDef |
46 | 46 |
from wcs.formdata import Evolution |
47 | 47 | |
48 |
from wcs.qommon.form import PicklableUpload as PUpload |
|
49 |
from collections import OrderedDict |
|
50 | ||
48 | 51 |
if not __name__.startswith('wcs.') and not __name__ == "__main__": |
49 | 52 |
raise ImportError('Import of workflows module must be absolute (import wcs.workflows)') |
50 | 53 | |
... | ... | |
1523 | 1526 |
ok_in_global_action = True # means it can be used in a global action |
1524 | 1527 |
directory_name = None |
1525 | 1528 |
directory_class = None |
1526 |
support_substitution_variables = False |
|
1529 | ||
1530 |
support_substitution_variables = True |
|
1531 |
attachments = None |
|
1532 | ||
1527 | 1533 | |
1528 | 1534 |
@classmethod |
1529 | 1535 |
def init(cls): |
... | ... | |
1603 | 1609 |
value=self.condition, size=40, |
1604 | 1610 |
advanced=not(self.condition)) |
1605 | 1611 | |
1612 |
if 'attachments' in parameters: |
|
1613 |
attachments_options, attachments = self.get_attachments_options() |
|
1614 |
if len(attachments_options) > 1: |
|
1615 |
form.add(WidgetList, '%sattachments' % prefix, title=_('Attachments'), |
|
1616 |
element_type=SingleSelectWidgetWithOther, |
|
1617 |
value=attachments, |
|
1618 |
add_element_label=_('Add attachment'), |
|
1619 |
element_kwargs={'render_br': False, 'options': attachments_options}) |
|
1620 |
else: |
|
1621 |
form.add(WidgetList, '%sattachments' % prefix, |
|
1622 |
title=_('Attachments (Python expressions)'), |
|
1623 |
element_type=StringWidget, |
|
1624 |
value=attachments, |
|
1625 |
add_element_label=_('Add attachment'), |
|
1626 |
element_kwargs={'render_br': False, 'size': 50}, |
|
1627 |
advanced=not(bool(attachments))) |
|
1628 | ||
1606 | 1629 |
def get_parameters(self): |
1607 | 1630 |
return ('condition',) |
1608 | 1631 | |
... | ... | |
1842 | 1865 |
del odict['parent'] |
1843 | 1866 |
return odict |
1844 | 1867 | |
1868 |
def attachments_init_with_xml(self, elem, charset, include_id=False): |
|
1869 |
if elem is None: |
|
1870 |
self.attachments = None |
|
1871 |
else: |
|
1872 |
self.attachments = [item.text.encode(charset) for item in elem.findall('attachment')] |
|
1873 | ||
1874 |
def get_attachments_options(self): |
|
1875 |
attachments_options = [(None, '---', None)] |
|
1876 |
varnameless = [] |
|
1877 |
for field in self.parent.parent.get_backoffice_fields(): |
|
1878 |
if field.key != 'file': |
|
1879 |
continue |
|
1880 |
if field.varname: |
|
1881 |
codename = 'form_var_%s_raw' % field.varname |
|
1882 |
else: |
|
1883 |
codename = 'form_f%s' % field.id # = form_fbo<n> |
|
1884 |
varnameless.append(codename) |
|
1885 |
attachments_options.append((codename, field.label, codename)) |
|
1886 |
# filter: do not consider removed fields without varname |
|
1887 |
attachments = [attachment for attachment in self.attachments or [] |
|
1888 |
if ((not attachment.startswith('form_fbo')) or |
|
1889 |
(attachment in varnameless))] |
|
1890 |
return attachments_options, attachments |
|
1891 | ||
1892 |
def get_attachment_varname(self, attachment, upload=None): |
|
1893 |
varname = str(attachment) |
|
1894 |
if isinstance(attachment, str) and re.match(r'form_var_', attachment): |
|
1895 |
varname = attachment |
|
1896 |
m = re.search(r'^form_var_(\w+)$', attachment) |
|
1897 |
if m: |
|
1898 |
varname = re.sub(r'_raw$', '', m.group(1)) if re.search(r'_raw$', m.group(1)) else m.group(1) |
|
1899 |
elif upload: |
|
1900 |
if isinstance(upload, PUpload): |
|
1901 |
varname = str(upload) |
|
1902 |
elif isinstance(upload, dict) and 'varname' in upload: |
|
1903 |
varname = upload['varname'] |
|
1904 |
elif hasattr(upload, varname): |
|
1905 |
varname = upload.varname |
|
1906 |
return varname |
|
1907 | ||
1908 |
def convert_attachments_to_uploads(self): |
|
1909 |
# forget previous attachment converted to uploads |
|
1910 |
# (file with same content and same varname, will not be duplicated |
|
1911 |
# because the path of the file is made of the hash of the content) |
|
1912 |
uploads = OrderedDict() |
|
1913 | ||
1914 |
if self.attachments: |
|
1915 |
global_eval_dict = get_publisher().get_global_eval_dict() |
|
1916 |
local_eval_dict = get_publisher().substitutions.get_context_variables() |
|
1917 |
for attachment in self.attachments: |
|
1918 |
try: |
|
1919 |
# execute any Python expression |
|
1920 |
# and magically convert string like 'form_var_*_raw' to a PicklableUpload |
|
1921 |
picklableupload = eval(attachment, global_eval_dict, local_eval_dict) |
|
1922 |
except: |
|
1923 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
1924 |
context='[workflow/attachments]') |
|
1925 |
continue |
|
1926 | ||
1927 |
if not picklableupload: |
|
1928 |
continue |
|
1929 | ||
1930 |
varname = self.get_attachment_varname(attachment, picklableupload) |
|
1931 | ||
1932 |
try: |
|
1933 |
# magically convert any value to a PicklableUpload |
|
1934 |
# usualy a dict like one provided by qommon/evalutils:attachment() |
|
1935 |
picklableupload = FileField.convert_value_from_anything(picklableupload) |
|
1936 |
except ValueError: |
|
1937 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
1938 |
context='[workflow/attachments]') |
|
1939 |
continue |
|
1940 | ||
1941 |
# exsiting attachments upload will be replaced by the new one (last one wins) |
|
1942 |
uploads[varname] = picklableupload |
|
1943 | ||
1944 |
return uploads |
|
1945 | ||
1946 |
def formdata_has_attachment(self, formdata, varname, attachment): |
|
1947 |
if not formdata.evolution or not formdata.evolution[-1].parts: |
|
1948 |
return False |
|
1949 |
if not varname and hasattr(attachment, 'varname'): |
|
1950 |
varname = attachment.varname |
|
1951 |
for part in formdata.evolution[-1].parts: |
|
1952 |
if isinstance(part, AttachmentEvolutionPart): |
|
1953 |
if attachment: |
|
1954 |
# not testing content here, only metadata |
|
1955 |
if part.orig_filename == attachment.orig_filename \ |
|
1956 |
and part.base_filename == attachment.base_filename \ |
|
1957 |
and part.content_type == attachment.content_type \ |
|
1958 |
and part.charset == attachment.charset \ |
|
1959 |
and (not varname or part.varname == varname): |
|
1960 |
return True |
|
1961 |
elif varname and part.varname == varname: |
|
1962 |
return True |
|
1963 |
return False |
|
1964 | ||
1965 |
def attach_uploads_to_formdata(self, formdata, uploads): |
|
1966 |
if not formdata.evolution[-1].parts: |
|
1967 |
formdata.evolution[-1].parts = [] |
|
1968 |
for varname, upload in uploads.items(): |
|
1969 |
# attach to form only if new (to prevent double attachments) |
|
1970 |
if not self.formdata_has_attachment(formdata, varname=varname, attachment=upload): |
|
1971 |
try: |
|
1972 |
# useless but required to restore upload.fp from serialized state, needed by 'AttachmentEvolutionPart.from_upload() |
|
1973 |
fp = upload.get_file_pointer() |
|
1974 |
formdata.evolution[-1].add_part(AttachmentEvolutionPart.from_upload(upload, varname=varname)) |
|
1975 |
except: |
|
1976 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
1977 |
context='[workflow/attachments]') |
|
1978 |
continue |
|
1979 | ||
1845 | 1980 | |
1846 | 1981 |
class WorkflowStatusJumpItem(WorkflowStatusItem): |
1847 | 1982 |
status = None |
... | ... | |
2182 | 2317 |
description = N_('Email') |
2183 | 2318 |
key = 'sendmail' |
2184 | 2319 |
category = 'interaction' |
2185 |
support_substitution_variables = True |
|
2186 | 2320 | |
2187 | 2321 |
to = [] |
2188 | 2322 |
subject = None |
2189 | 2323 |
body = None |
2190 | 2324 |
custom_from = None |
2191 |
attachments = None |
|
2192 | 2325 | |
2193 | 2326 |
comment = None |
2194 | 2327 | |
... | ... | |
2204 | 2337 |
return super(SendmailWorkflowStatusItem, self)._get_role_id_from_xml( |
2205 | 2338 |
elem, charset, include_id=include_id) |
2206 | 2339 | |
2207 |
def attachments_init_with_xml(self, elem, charset, include_id=False): |
|
2208 |
if elem is None: |
|
2209 |
self.attachments = None |
|
2210 |
else: |
|
2211 |
self.attachments = [item.text.encode(charset) for item in elem.findall('attachment')] |
|
2212 | ||
2213 | 2340 |
def render_list_of_roles_or_emails(self, roles): |
2214 | 2341 |
t = [] |
2215 | 2342 |
for r in roles: |
... | ... | |
2239 | 2366 |
def fill_admin_form(self, form): |
2240 | 2367 |
self.add_parameters_widgets(form, self.get_parameters()) |
2241 | 2368 | |
2242 |
def get_attachments_options(self): |
|
2243 |
attachments_options = [(None, '---', None)] |
|
2244 |
varnameless = [] |
|
2245 |
for field in self.parent.parent.get_backoffice_fields(): |
|
2246 |
if field.key != 'file': |
|
2247 |
continue |
|
2248 |
if field.varname: |
|
2249 |
codename = 'form_var_%s_raw' % field.varname |
|
2250 |
else: |
|
2251 |
codename = 'form_f%s' % field.id # = form_fbo<n> |
|
2252 |
varnameless.append(codename) |
|
2253 |
attachments_options.append((codename, field.label, codename)) |
|
2254 |
# filter: do not consider removed fields without varname |
|
2255 |
attachments = [attachment for attachment in self.attachments or [] |
|
2256 |
if ((not attachment.startswith('form_fbo')) or |
|
2257 |
(attachment in varnameless))] |
|
2258 |
return attachments_options, attachments |
|
2259 | ||
2260 | 2369 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): |
2261 | 2370 |
super(SendmailWorkflowStatusItem, self).add_parameters_widgets( |
2262 | 2371 |
form, parameters, prefix=prefix, formdef=formdef) |
... | ... | |
2277 | 2386 |
value=self.body, cols=80, rows=10, |
2278 | 2387 |
validation_function=ComputedExpressionWidget.validate_template) |
2279 | 2388 | |
2280 |
if 'attachments' in parameters: |
|
2281 |
attachments_options, attachments = self.get_attachments_options() |
|
2282 |
if len(attachments_options) > 1: |
|
2283 |
form.add(WidgetList, '%sattachments' % prefix, title=_('Attachments'), |
|
2284 |
element_type=SingleSelectWidgetWithOther, |
|
2285 |
value=attachments, |
|
2286 |
add_element_label=_('Add attachment'), |
|
2287 |
element_kwargs={'render_br': False, 'options': attachments_options}) |
|
2288 |
else: |
|
2289 |
form.add(WidgetList, '%sattachments' % prefix, |
|
2290 |
title=_('Attachments (Python expressions)'), |
|
2291 |
element_type=StringWidget, |
|
2292 |
value=attachments, |
|
2293 |
add_element_label=_('Add attachment'), |
|
2294 |
element_kwargs={'render_br': False, 'size': 50}, |
|
2295 |
advanced=not(bool(attachments))) |
|
2296 | ||
2297 | 2389 |
if 'custom_from' in parameters: |
2298 | 2390 |
form.add(ComputedExpressionWidget, '%scustom_from' % prefix, |
2299 | 2391 |
title=_('Custom From Address'), value=self.custom_from, |
... | ... | |
2381 | 2473 |
if self.custom_from: |
2382 | 2474 |
email_from = self.compute(self.custom_from) |
2383 | 2475 | |
2384 |
attachments = [] |
|
2385 |
if self.attachments: |
|
2386 |
global_eval_dict = get_publisher().get_global_eval_dict() |
|
2387 |
local_eval_dict = get_publisher().substitutions.get_context_variables() |
|
2388 |
for attachment in self.attachments: |
|
2389 |
try: |
|
2390 |
picklableupload = eval(attachment, global_eval_dict, local_eval_dict) |
|
2391 |
except: |
|
2392 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
2393 |
context='[Sendmail/attachments]') |
|
2394 |
continue |
|
2395 |
if not picklableupload: |
|
2396 |
continue |
|
2397 |
try: |
|
2398 |
picklableupload = FileField.convert_value_from_anything(picklableupload) |
|
2399 |
except ValueError: |
|
2400 |
get_publisher().notify_of_exception(sys.exc_info(), |
|
2401 |
context='[Sendmail/attachments]') |
|
2402 |
continue |
|
2403 |
attachments.append(picklableupload) |
|
2476 |
attachments = [x for _,x in self.convert_attachments_to_uploads().items()] |
|
2404 | 2477 | |
2405 | 2478 |
if len(addresses) > 1: |
2406 | 2479 |
emails.email(mail_subject, mail_body, email_rcpt=None, |
2407 |
- |