Skip to content

Commit be373c8

Browse files
committed
Rework email send as a reference in context and provide its fake.
Use the runtime configuration and its persistent context as the means to expose the email sending logic to codepaths making use of it. This allow centralised control over the active email sending implementation without having to thread extra arguments through internal codepaths. As a result, we are able to centrally intercept email sending. Do this, and as a consequence sprinkle a bunch of additional assertions into calls that happen to send email but this side-effect was completely uncovered. Add a means for tests to check the the number of emails sent and whether an email was sent to a particular recipient. For cases where the email sent is not relevant to what is being tested, there is an escape hatch.
1 parent 09bee5a commit be373c8

16 files changed

Lines changed: 226 additions & 71 deletions

mig/server/grid_notify.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,10 @@ def send_notifications(configuration):
130130
notify_message = "Found %s new events since: %s\n\n" \
131131
% (total_events, timestr) \
132132
+ notify_message
133-
status = send_email(
133+
status = send_email(configuration,
134134
recipient,
135135
subject,
136-
notify_message,
137-
logger,
138-
configuration)
136+
notify_message)
139137
if status:
140138
logger.info("Send email with %s events to: %s"
141139
% (total_events, recipient))

mig/shared/functionality/autocreate.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,7 @@ def main(client_id, user_arguments_dict, environ=None):
740740
logger.info('Send email: to: %s, header: %s, smtp_server: %s'
741741
% (email, email_header, smtp_server))
742742
logger.debug('email body: %s' % email_msg)
743-
if not send_email(email, email_header, email_msg, logger,
744-
configuration):
743+
if not send_email(configuration, email, email_header, email_msg):
745744
output_objects.append({
746745
'object_type': 'error_text', 'text': """An error occurred trying
747746
to send your account welcome email. Please contact support (%s) and include the

mig/shared/functionality/extcertaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,7 @@ def main(client_id, user_arguments_dict):
316316

317317
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
318318
% (admin_email, email_header, email_msg, smtp_server))
319-
if not send_email(admin_email, email_header, email_msg, logger,
320-
configuration):
319+
if not send_email(configuration, admin_email, email_header, email_msg):
321320
output_objects.append({'object_type': 'error_text', 'text':
322321
"""An error occurred trying to inform the site
323322
admins about your request for existing certificate sign up. Please contact %s site

mig/shared/functionality/extoidaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,7 @@ def main(client_id, user_arguments_dict):
282282

283283
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
284284
% (admin_email, email_header, email_msg, smtp_server))
285-
if not send_email(admin_email, email_header, email_msg, logger,
286-
configuration):
285+
if not send_email(configuration, admin_email, email_header, email_msg):
287286
output_objects.append({'object_type': 'error_text', 'text':
288287
"""An error occurred trying to inform the site
289288
admins about your request for OpenID account access. Please contact %s site

mig/shared/functionality/peersaction.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ def main(client_id, user_arguments_dict):
309309
logger.info('Sending invitation: to: %s, header: %s, msg: %s, smtp_server: %s'
310310
% (peer_email, email_header, email_msg,
311311
smtp_server))
312-
if send_email(peer_email, email_header, email_msg, logger,
313-
configuration):
312+
if send_email(configuration, peer_email, email_header, email_msg):
314313
succeeded.append(peer_email)
315314
else:
316315
failed.append(peer_email)
@@ -369,8 +368,7 @@ def main(client_id, user_arguments_dict):
369368

370369
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
371370
% (admin_email, email_header, email_msg, smtp_server))
372-
if not send_email(admin_email, email_header, email_msg, logger,
373-
configuration):
371+
if not send_email(configuration, admin_email, email_header, email_msg):
374372
output_objects.append({'object_type': 'error_text', 'text': '''
375373
An error occurred trying to send the email about your %s peers to the site
376374
administrators. Please contact %s site support at %s or manually inform the

mig/shared/functionality/reqcertaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,7 @@ def main(client_id, user_arguments_dict):
346346

347347
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
348348
% (admin_email, email_header, email_msg, smtp_server))
349-
if not send_email(admin_email, email_header, email_msg, logger,
350-
configuration):
349+
if not send_email(configuration, admin_email, email_header, email_msg):
351350
output_objects.append({'object_type': 'error_text', 'text':
352351
"""An error occurred trying to inform the site
353352
admins about your request for certificate sign up. Please contact %s site

mig/shared/functionality/reqoidaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,7 @@ def main(client_id, user_arguments_dict):
357357

358358
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
359359
% (admin_email, email_header, email_msg, smtp_server))
360-
if not send_email(admin_email, email_header, email_msg, logger,
361-
configuration):
360+
if not send_email(configuration, admin_email, email_header, email_msg):
362361
output_objects.append({'object_type': 'error_text', 'text':
363362
"""An error occurred trying to inform the site
364363
admins about your request for OpenID account access. Please contact %s site

mig/shared/functionality/reqpwresetaction.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ def main(client_id, user_arguments_dict):
271271

272272
logger.info('Sending email: to: %s, header: %s, msg: %s, smtp_server: %s'
273273
% (email_to, email_header, email_msg, smtp_server))
274-
if not send_email(email_to, email_header, email_msg, logger,
275-
configuration):
274+
if not send_email(configuration, email_to, email_header, email_msg):
276275
output_objects.append({'object_type': 'error_text', 'text':
277276
"""An error occurred trying to send the email
278277
for an account %s password reset request. Please contact %s site support at %s

mig/shared/gdp/base.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -683,12 +683,10 @@ def __send_project_action_confirmation(configuration,
683683
684684
Attached you'll find the details registered in relation to the operation.
685685
""" % mail_fill
686-
status = send_email(
686+
status = send_email(configuration,
687687
recipients,
688688
subject,
689689
message,
690-
_logger,
691-
configuration,
692690
files=[pdf_filepath],
693691
)
694692
if status:

mig/shared/notification.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252

5353
from mig.shared.base import force_utf8, generate_https_urls, extract_field, \
5454
canonical_user_with_peers, cert_field_map, get_site_base_url
55+
from mig.shared.conf import RuntimeConfiguration
5556
from mig.shared.defaults import email_keyword_list, job_output_dir, \
5657
transfer_output_dir, keyword_auto, cert_auto_extend_days, \
5758
oid_auto_extend_days
@@ -561,11 +562,35 @@ def send_instant_message(
561562

562563

563564
def send_email(
565+
configuration,
566+
recipients,
567+
subject,
568+
message,
569+
files=[],
570+
custom_sender=None):
571+
"""Send email to recipients via the actively configured method."""
572+
573+
assert RuntimeConfiguration.is_runtime_configuration(configuration)
574+
575+
notifier = configuration.context_get('notifier')
576+
if not notifier:
577+
notifier = Notifier(configuration)
578+
configuration.context_set('notifier', notifier)
579+
580+
return notifier.send_email(
581+
recipients,
582+
subject,
583+
message,
584+
files=files,
585+
custom_sender=custom_sender,
586+
)
587+
588+
589+
def direct_send_email(
590+
configuration,
564591
recipients,
565592
subject,
566593
message,
567-
logger,
568-
configuration,
569594
files=[],
570595
custom_sender=None
571596
):
@@ -589,13 +614,14 @@ def send_email(
589614
"""
590615

591616
_logger = configuration.logger
617+
592618
gpg_sign = False
593619
if configuration.site_gpg_passphrase is not None:
594620
if gnupg is None:
595-
logger.warning("the gnupg module is required for gpg signing")
621+
_logger.warning("the gnupg module is required for gpg signing")
596622
else:
597623
gpg_sign = True
598-
logger.debug("enabling automatic gpg signing of email")
624+
_logger.debug("enabling automatic gpg signing of email")
599625

600626
if recipients.find(', ') > -1:
601627
recipients_list = recipients.split(', ')
@@ -631,7 +657,7 @@ def send_email(
631657
basemsg = MIMEText(force_utf8(message), "plain", "utf8")
632658
mime_msg.attach(basemsg)
633659
if gpg_sign:
634-
logger.info("signing message with gpg")
660+
_logger.info("signing message with gpg")
635661
gpg = gnupg.GPG()
636662
basetext = basemsg.as_string().replace('\n', '\r\n')
637663
signature = gpg.sign(basetext, detach=True,
@@ -643,7 +669,7 @@ def send_email(
643669
msg_sig.set_payload("%s" % signature)
644670
mime_msg.attach(msg_sig)
645671
else:
646-
logger.warning("failed to create gnupg signature")
672+
_logger.warning("failed to create gnupg signature")
647673

648674
for name in files:
649675
part = MIMEBase('application', "octet-stream")
@@ -652,7 +678,7 @@ def send_email(
652678
part.add_header('Content-Disposition',
653679
'attachment', filename=os.path.basename(name))
654680
mime_msg.attach(part)
655-
logger.debug('sending email from %s to %s:\n%s' %
681+
_logger.debug('sending email from %s to %s:\n%s' %
656682
(from_email, recipients, mime_msg.as_string()))
657683
server = smtplib.SMTP(configuration.smtp_server)
658684
server.set_debuglevel(0)
@@ -664,10 +690,10 @@ def send_email(
664690
% errors)
665691
return False
666692
else:
667-
logger.debug('Email was sent to %s' % recipients)
693+
_logger.debug('Email was sent to %s' % recipients)
668694
return True
669695
except Exception as err:
670-
logger.error('Sending email to %s through %s failed!: %s'
696+
_logger.error('Sending email to %s through %s failed!: %s'
671697
% (recipients, configuration.smtp_server, err))
672698
return False
673699

@@ -819,8 +845,8 @@ def notify_user(
819845

820846
continue
821847

822-
if send_email(single_dest, header, message, logger,
823-
configuration, custom_sender=email_sender):
848+
if send_email(configuration, single_dest, header, message,
849+
custom_sender=email_sender):
824850
logger.info('email sent to %s telling that %s %s'
825851
% (single_dest, jobid, status))
826852
else:
@@ -906,7 +932,7 @@ def send_resource_create_request_mail(
906932
os.path.basename(pending_file),
907933
)
908934

909-
status = send_email(recipients, subject, txt, logger, configuration)
935+
status = send_email(configuration, recipients, subject, txt)
910936
if status:
911937
msg += '\nEmail was sent to admins'
912938
else:
@@ -961,3 +987,13 @@ def send_system_notification(user_id, category, message, configuration):
961987
return send_message_to_grid_notify(pickled_notification,
962988
configuration.logger,
963989
configuration)
990+
991+
992+
class Notifier:
993+
def __init__(self, configuration):
994+
self.configuration = configuration
995+
996+
def send_email(self, recipients, subject, message, files=[], custom_sender=None):
997+
return direct_send_email(self.configuration, recipients, subject, message,
998+
files=[],
999+
custom_sender=None)

0 commit comments

Comments
 (0)