workflows: allow sending emails to lazy lists (#63778)

This commit is contained in:
Frédéric Péters 2022-04-10 19:45:22 +02:00
parent aac0672183
commit 6b59e36145
2 changed files with 120 additions and 22 deletions

View File

@ -119,7 +119,7 @@ def test_email(pub, emails):
get_response().process_after_jobs()
assert emails.count() == 1
assert emails.get('foobar')['to'] == 'Undisclosed recipients:;'
assert emails.get('foobar')['email_rcpt'] == ['foo@localhost', 'bar@localhost', 'baz@localhost']
assert set(emails.get('foobar')['email_rcpt']) == {'foo@localhost', 'bar@localhost', 'baz@localhost'}
# submitter as recipient, no known email address
emails.empty()
@ -151,7 +151,7 @@ def test_email(pub, emails):
item.perform(formdata)
get_response().process_after_jobs()
assert emails.count() == 1
assert emails.get('foobar')['email_rcpt'] == ['foo@localhost', 'bar@localhost']
assert set(emails.get('foobar')['email_rcpt']) == {'foo@localhost', 'bar@localhost'}
# multiple recipients in a single computed string
emails.empty()
@ -159,7 +159,7 @@ def test_email(pub, emails):
item.perform(formdata)
get_response().process_after_jobs()
assert emails.count() == 1
assert emails.get('foobar')['email_rcpt'] == ['foo@localhost', 'bar@localhost']
assert set(emails.get('foobar')['email_rcpt']) == {'foo@localhost', 'bar@localhost'}
# string as recipient
emails.empty()
@ -183,7 +183,7 @@ def test_email(pub, emails):
item.perform(formdata)
get_response().process_after_jobs()
assert emails.count() == 1
assert emails.get('foobar')['email_rcpt'] == ['foo@localhost', 'bar@localhost']
assert set(emails.get('foobar')['email_rcpt']) == {'foo@localhost', 'bar@localhost'}
# invalid recipient
emails.empty()
@ -588,3 +588,76 @@ def test_email_part(pub, emails):
assert substvars['form_workflow_email_zzz_1_subject'] == 'foobar2'
# check non-indexed access gives the latest value
assert substvars['form_workflow_email_zzz_subject'] == 'foobar2'
def test_email_computed_recipients(pub, emails):
pub.user_class.wipe()
FormDef.wipe()
user1 = pub.user_class(name='userA')
user1.name_identifiers = ['xxy1']
user1.email = 'user1@example.com'
user1.store()
user2 = pub.user_class(name='userB')
user2.name_identifiers = ['xxy2']
user2.email = 'user2@example.com'
user2.store()
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = []
formdef.store()
formdef.data_class().wipe()
formdatas = []
for i in range(2):
formdatas.append(formdef.data_class()())
formdatas[0].user_id = user1.id
formdatas[1].user_id = user2.id
for formdata in formdatas:
formdata.just_created()
formdata.store()
formdef = FormDef()
formdef.name = 'baz'
formdef.fields = []
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
item = SendmailWorkflowStatusItem()
item.varname = 'test'
item.to = []
item.subject = 'xxx'
item.body = 'XXX'
for recipient in [
'user1@example.com,user2@example.com',
'{% for obj in forms|objects:"foo" %}{{ obj|get:"form_user_email" }},{% endfor %}',
'{{ forms|objects:"foo"|getlist:"form_user_email" }}',
'{{ forms|objects:"foo"|getlist:"form_user_email"|list }}',
'{{ forms|objects:"foo"|getlist:"form_user" }}',
'{{ forms|objects:"foo"|getlist:"form_user"|list }}',
]:
item.to = [recipient]
emails.empty()
item.perform(formdata)
get_response().process_after_jobs()
assert emails.count() == 1
assert set(formdata.evolution[-1].parts[-1].addresses) == {'user1@example.com', 'user2@example.com'}
formdata.evolution[-1].parts = []
formdata.user_id = user1.id
pub.substitutions.feed(formdata)
item.to = ['{{form_user}}']
emails.empty()
item.perform(formdata)
get_response().process_after_jobs()
assert emails.count() == 1
assert set(formdata.evolution[-1].parts[-1].addresses) == {'user1@example.com'}
formdata.evolution[-1].parts = []

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import collections.abc
from django.utils.timezone import now
from quixote import get_publisher
from quixote.html import htmltext
@ -31,6 +33,7 @@ from wcs.qommon.form import (
)
from wcs.qommon.misc import xml_node_text
from wcs.qommon.template import TemplateError
from wcs.variables import LazyList, LazyUser
from wcs.workflows import (
EvolutionPart,
WorkflowImportUnknownReferencedError,
@ -267,33 +270,44 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem):
if isinstance(self.to, str):
self.to = [self.to]
addresses = []
dests = []
for dest in self.to:
try:
dest = self.compute(dest, raises=True)
except Exception:
continue
with get_publisher().complex_data():
try:
dest = self.compute(dest, allow_complex=True, raises=True)
except Exception:
continue
else:
dest = get_publisher().get_cached_complex_data(dest)
if not dest:
continue
if isinstance(dest, list):
addresses.extend(dest)
continue
if isinstance(dest, str) and ',' in dest:
# if the email contains a comma consider it as a serie of
# emails
addresses.extend([x.strip() for x in dest.split(',')])
if isinstance(dest, (LazyUser, get_publisher().user_class)):
dests.append(dest)
continue
if '@' in str(dest):
addresses.append(dest)
if not isinstance(dest, str):
if isinstance(dest, LazyList):
dest = list(dest)
if isinstance(dest, collections.abc.Iterable):
dests.extend(dest)
continue
if ',' in dest:
# if the email contains a comma consider it as a serie of
# emails
dests.extend([x.strip() for x in dest.split(',')])
continue
if '@' in dest:
dests.append(dest)
continue
if dest == '_submitter':
submitter_email = formdata.formdef.get_submitter_email(formdata)
if submitter_email:
addresses.append(submitter_email)
dests.append(submitter_email)
continue
for real_dest in formdata.get_function_roles(dest):
@ -302,15 +316,26 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem):
user = get_publisher().user_class.get(real_dest.split(':')[1])
except KeyError:
continue
if user.email:
addresses.append(user.email)
dests.append(user)
continue
try:
role = get_publisher().role_class.get(real_dest)
except KeyError:
continue
addresses.extend(role.get_emails())
dests.extend(role.get_emails())
addresses = set()
for value in dests:
if not value:
continue
if isinstance(value, LazyUser):
value = value._user
if isinstance(value, get_publisher().user_class):
if value.email:
addresses.add(value.email)
continue
addresses.add(value)
if not addresses:
return