Makes sure BCC is provided to *every* e-mail. (#65)
* Replaces the monkey patch on send_mail, and replaces it with a monkey patch on EmailMessage’s constructor. * Removes spurious print statements. * Minimum viable changes to get schedule to display (#64) * All migrations are now in this tree * Replaces the monkey patch on send_mail, and replaces it with a monkey patch on EmailMessage’s constructor. * Removes spurious print statements.
This commit is contained in:
		
							parent
							
								
									fe31b1b7c4
								
							
						
					
					
						commit
						7a001e6228
					
				
					 1 changed files with 77 additions and 17 deletions
				
			
		|  | @ -12,7 +12,7 @@ class MonkeyPatchMiddleware(object): | ||||||
| 
 | 
 | ||||||
| def do_monkey_patch(): | def do_monkey_patch(): | ||||||
|     patch_speaker_profile_form() |     patch_speaker_profile_form() | ||||||
|     patch_accounts_to_send_bcc() |     patch_mail_to_send_bcc() | ||||||
|     fix_sitetree_check_access_500s() |     fix_sitetree_check_access_500s() | ||||||
|     never_cache_login_page() |     never_cache_login_page() | ||||||
| 
 | 
 | ||||||
|  | @ -33,31 +33,91 @@ def patch_speaker_profile_form(): | ||||||
|     fields["accessibility"].widget = widgets.AceMarkdownEditor() |     fields["accessibility"].widget = widgets.AceMarkdownEditor() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def patch_accounts_to_send_bcc(): | def patch_mail_to_send_bcc(): | ||||||
|     ''' Patches django-user-accounts' email functions to send a BCC e-mail to |     ''' Patches django.core.mail's message classes to send a BCC e-mail to | ||||||
|     the default BCC e-mail address. ''' |     the default BCC e-mail address. ''' | ||||||
| 
 | 
 | ||||||
|     from account import hooks |     from django.core.mail import message | ||||||
| 
 | 
 | ||||||
|     # django-user-accounts always uses send_mail like: |     ARG = "bcc" | ||||||
|     # send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, to) |  | ||||||
| 
 | 
 | ||||||
|     if hasattr(settings, "ENVELOPE_BCC_LIST"): |     if hasattr(settings, "ENVELOPE_BCC_LIST"): | ||||||
|         bcc_email = settings.ENVELOPE_BCC_LIST |         bcc_email = settings.ENVELOPE_BCC_LIST | ||||||
|     else: |     else: | ||||||
|         bcc_email = None |         return  # We don't need to do this patch. | ||||||
| 
 | 
 | ||||||
|     def send_mail(subject, message, from_email, to): |     def bcc_arg_position(f): | ||||||
|         email = EmailMultiAlternatives( |         ''' Returns the position of 'bcc' in the argument list to f, or None if | ||||||
|             subject, |         there is no such argument. ''' | ||||||
|             message, |         co = f.__code__ | ||||||
|             from_email, |         # The first co_argcount members of co_varnames are argument variables | ||||||
|             to, |         for i, argname in enumerate(co.co_varnames[:co.co_argcount]): | ||||||
|             bcc=bcc_email, |             if argname == ARG: | ||||||
|         ) |                 return i | ||||||
|         email.send() |         else: | ||||||
|  |             return None | ||||||
| 
 | 
 | ||||||
|     hooks.send_mail = send_mail |     def bcc_is_provided_positionally(f, a): | ||||||
|  |         ''' Returns true if 'bcc' is provided as a positional argument to f, | ||||||
|  |         when it is called with the argument list `a`. ''' | ||||||
|  | 
 | ||||||
|  |         return bcc_arg_position(f) < len(a) | ||||||
|  | 
 | ||||||
|  |     def patch_bcc_positional(f, a): | ||||||
|  |         ''' Returns a copy of `a`, but with the bcc argument patched to include | ||||||
|  |         our BCC list. ''' | ||||||
|  | 
 | ||||||
|  |         pos = bcc_arg_position(f) | ||||||
|  |         bcc = a[pos] | ||||||
|  | 
 | ||||||
|  |         if bcc is not None: | ||||||
|  |             bcc = list(bcc) | ||||||
|  |         else: | ||||||
|  |             bcc = [] | ||||||
|  | 
 | ||||||
|  |         bcc += bcc_email | ||||||
|  | 
 | ||||||
|  |         return tuple(a[:pos] + (bcc,) + a[pos + 1:]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def patch_bcc_keyword(f, k): | ||||||
|  |         ''' Adds our BCC list to the BCC list in the keyword arguments, and | ||||||
|  |         returns the new version of the keyword arguments. | ||||||
|  | 
 | ||||||
|  |         Arguments: | ||||||
|  |             f (callable): The function that we're patching. It should have an | ||||||
|  |                 argument called bcc. | ||||||
|  |             k (dict): A dictionary of kwargs to be provided to EmailMessage. | ||||||
|  |             It will be modified to add the BCC list specified in | ||||||
|  |             settings.ENVELOPE_BCC_LIST, if provided. | ||||||
|  |         ''' | ||||||
|  | 
 | ||||||
|  |         if ARG in k: | ||||||
|  |             bcc = list(k[ARG]) | ||||||
|  |             del k[ARG] | ||||||
|  |         else: | ||||||
|  |             bcc = [] | ||||||
|  |         bcc += list(bcc_email) | ||||||
|  |         k[ARG] = bcc | ||||||
|  | 
 | ||||||
|  |         return k | ||||||
|  | 
 | ||||||
|  |     to_wrap = message.EmailMessage.__init__ | ||||||
|  |      | ||||||
|  |     @wraps(to_wrap) | ||||||
|  |     def email_message__init__(*a, **k): | ||||||
|  | 
 | ||||||
|  |         if bcc_is_provided_positionally(to_wrap, a): | ||||||
|  |             a = patch_bcc_positional(to_wrap, a) | ||||||
|  |         else: | ||||||
|  |             k = patch_bcc_keyword(to_wrap, k) | ||||||
|  | 
 | ||||||
|  |         return to_wrap(*a, **k) | ||||||
|  | 
 | ||||||
|  |     message.EmailMessage.__init__ = email_message__init__ | ||||||
|  | 
 | ||||||
|  |     # Do not need to wrap EmailMultiAlternatives because it is a subclass of | ||||||
|  |     # EmailMessage. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def fix_sitetree_check_access_500s(): | def fix_sitetree_check_access_500s(): | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer