def test_html_template(self): '''Assert that we may add an additional text template to the email engine. ''' factory = EmailFactory('*****@*****.**', 'test_subject', 'test.txt', 'plugin.email') factory.add_text_template('test.html', 'html') msg = factory.build('*****@*****.**', test_parameter='value') # Assert that the message is multipart self.assertTrue(msg.is_multipart()) self.assertEqual(2, len(msg.get_payload())) payload_text = msg.get_payload(0) self.assertEqual('text/plain; charset="utf-8"', payload_text.get('Content-Type')) self.assertEqual(b'value', payload_text.get_payload(decode=True)) payload_html = msg.get_payload(1) self.assertEqual('text/html; charset="utf-8"', payload_html.get('Content-Type')) self.assertEqual(b'value', payload_html.get_payload(decode=True))
def test_html_template(self): '''Assert that we may add an additional text template to the email engine. ''' factory = EmailFactory('*****@*****.**', 'test_subject.txt', 'test.txt', 'plugin.email') factory.add_text_template('test.html', 'html') msg = factory.build('*****@*****.**', test_parameter='value') # Assert that the message is multipart self.assertTrue(msg.is_multipart()) self.assertEqual(2, len(msg.get_payload())) payload_text = msg.get_payload(0) self.assertEqual('text/plain; charset="utf-8"', payload_text.get('Content-Type')) self.assertEqual(b'value', payload_text.get_payload(decode=True)) payload_html = msg.get_payload(1) self.assertEqual('text/html; charset="utf-8"', payload_html.get('Content-Type')) self.assertEqual(b'value', payload_html.get_payload(decode=True))
def test_no_template(self): """Assert that attempting to load an invalid template raises an exception. """ try: EmailFactory('*****@*****.**', 'test_subject', 'invalid.txt', 'plugin.email') self.assertFalse(True) except TemplateNotFound: self.assertFalse(False) try: factory = EmailFactory('*****@*****.**', 'test_subject', 'test.txt', 'plugin.email') factory.add_text_template('invalid.html', 'html') self.assertFalse(True) except TemplateNotFound: self.assertFalse(False)
def test_no_template(self): """Assert that attempting to load an invalid template raises an exception. """ try: EmailFactory('*****@*****.**', 'invalid_subject.txt', 'invalid.txt', 'plugin.email') self.assertFalse(True) except TemplateNotFound: self.assertFalse(False) try: factory = EmailFactory('*****@*****.**', 'test_subject.txt', 'test.txt', 'plugin.email') factory.add_text_template('invalid.html', 'html') self.assertFalse(True) except TemplateNotFound: self.assertFalse(False)
def handle_email(self, session, author, subscribers, method, url, path, query_string, status, resource, resource_id, sub_resource=None, sub_resource_id=None, resource_before=None, resource_after=None): """Send an email for a specific event. We assume that filtering logic has already occurred when this method is invoked. :param session: An event-specific SQLAlchemy session. :param author: The author's user record. :param subscribers: A list of subscribers that should receive an email. :param method: The HTTP Method. :param url: The Referer header from the request. :param path: The full HTTP Path requested. :param query_string: The query string from the request. :param status: The returned HTTP Status of the response. :param resource: The resource type. :param resource_id: The ID of the resource. :param sub_resource: The subresource type. :param sub_resource_id: The ID of the subresource. :param resource_before: The resource state before this event occurred. :param resource_after: The resource state after this event occurred. """ email_config = CONF.plugin_email # Retrieve the template names. (subject_template, text_template, html_template) = \ self.get_templates(method=method, resource_name=resource, sub_resource_name=sub_resource) # Build our factory. If an HTML template exists, add it. If it can't # find the template, skip. try: factory = EmailFactory(sender=email_config.sender, subject=subject_template, text_template=text_template) except TemplateNotFound: LOG.error("Templates not found [%s, %s]" % (subject_template, text_template)) return # Try to add an HTML template try: factory.add_text_template(html_template, 'html') except TemplateNotFound: LOG.debug('Template %s not found' % (html_template, )) # If there's a reply-to in our config, add that. if email_config.reply_to: factory.add_header('Reply-To', email_config.reply_to) # If there is a fallback URL configured, use it if needed if email_config.default_url and url is None: url = email_config.default_url # Resolve the resource instance resource_instance = self.resolve_resource_by_name( session, resource, resource_id) sub_resource_instance = self.resolve_resource_by_name( session, sub_resource, sub_resource_id) # Set In-Reply-To message id for 'task', 'story', and # 'worklist' resources story_id = None worklist_id = None if resource == 'task' and method == 'DELETE': # FIXME(pedroalvarez): Workaround the fact that the task won't be # in the database anymore if it has been deleted. # We should archive instead of delete to solve this. story_id = resource_before['story_id'] created_at = self.resolve_resource_by_name(session, 'story', story_id).created_at elif resource == 'task': story_id = resource_instance.story.id created_at = resource_instance.story.created_at elif resource == 'story': story_id = resource_instance.id created_at = resource_instance.created_at elif resource == 'worklist': worklist_id = resource_instance.id created_at = resource_instance.created_at if story_id and created_at: thread_id = "<storyboard.story.%s.%s@%s>" % ( created_at.strftime("%Y%m%d%H%M"), story_id, getfqdn()) elif worklist_id and created_at: thread_id = "<storyboard.worklist.%s.%s@%s>" % ( created_at.strftime("%Y%m%d%H%M"), story_id, getfqdn()) else: thread_id = make_msgid() factory.add_header("In-Reply-To", thread_id) factory.add_header("X-StoryBoard-Subscription-Type", resource) # Figure out the diff between old and new. before, after = self.get_changed_properties(resource_before, resource_after) # For each subscriber, create the email and send it. with smtp.get_smtp_client() as smtp_client: for subscriber in subscribers: # Make sure this subscriber's preferences indicate they want # email and they're not receiving digests. if not self.get_preference('plugin_email_enable', subscriber) \ or self.get_preference('plugin_email_digest', subscriber): continue send_notification = self.get_preference( 'receive_notifications_worklists', subscriber) if send_notification != 'true' and story_id is None: continue # Don't send a notification if the user isn't allowed to see # the thing this event is about. if 'event_type' in resource: event = events_api.event_get(resource['id'], current_user=subscriber.id, session=session) if not events_api.is_visible( event, subscriber.id, session=session): continue try: # Build an email. message = factory.build(recipient=subscriber.email, author=author, resource=resource_instance, sub_resource=sub_resource_instance, url=url, query_string=query_string, before=before, after=after) # Send the email. from_addr = message.get('From') to_addrs = message.get('To') try: smtp_client.sendmail(from_addr=from_addr, to_addrs=to_addrs, msg=message.as_string()) except smtplib.SMTPException as e: LOG.error('Cannot send email, discarding: %s' % (e, )) except Exception as e: # Skip, keep going. LOG.error("Cannot schedule email: %s" % (e.message, ))
def handle_email(self, session, author, subscribers, method, url, path, query_string, status, resource, resource_id, sub_resource=None, sub_resource_id=None, resource_before=None, resource_after=None): """Send an email for a specific event. We assume that filtering logic has already occurred when this method is invoked. :param session: An event-specific SQLAlchemy session. :param author: The author's user record. :param subscribers: A list of subscribers that should receive an email. :param method: The HTTP Method. :param url: The Referer header from the request. :param path: The full HTTP Path requested. :param query_string: The query string from the request. :param status: The returned HTTP Status of the response. :param resource: The resource type. :param resource_id: The ID of the resource. :param sub_resource: The subresource type. :param sub_resource_id: The ID of the subresource. :param resource_before: The resource state before this event occurred. :param resource_after: The resource state after this event occurred. """ email_config = CONF.plugin_email # Retrieve the template names. (subject_template, text_template, html_template) = \ self.get_templates(method=method, resource_name=resource, sub_resource_name=sub_resource) # Build our factory. If an HTML template exists, add it. If it can't # find the template, skip. try: factory = EmailFactory(sender=email_config.sender, subject=subject_template, text_template=text_template) except TemplateNotFound: LOG.error("Templates not found [%s, %s]" % (subject_template, text_template)) return # Try to add an HTML template try: factory.add_text_template(html_template, 'html') except TemplateNotFound: LOG.debug('Template %s not found' % (html_template, )) # If there's a reply-to in our config, add that. if email_config.reply_to: factory.add_header('Reply-To', email_config.reply_to) # Resolve the resource instance resource_instance = self.resolve_resource_by_name( session, resource, resource_id) sub_resource_instance = self.resolve_resource_by_name( session, sub_resource, sub_resource_id) # Figure out the diff between old and new. before, after = self.get_changed_properties(resource_before, resource_after) # For each subscriber, create the email and send it. with smtp.get_smtp_client() as smtp_client: for subscriber in subscribers: # Make sure this subscriber's preferences indicate they want # email and they're not receiving digests. if not self.get_preference('plugin_email_enable', subscriber) \ or self.get_preference('plugin_email_digest', subscriber): continue try: # Build an email. message = factory.build(recipient=subscriber.email, author=author, resource=resource_instance, sub_resource=sub_resource_instance, url=url, query_string=query_string, before=before, after=after) # Send the email. from_addr = message.get('From') to_addrs = message.get('To') try: smtp_client.sendmail(from_addr=from_addr, to_addrs=to_addrs, msg=message.as_string()) except smtplib.SMTPException as e: LOG.error('Cannot send email, discarding: %s' % (e, )) except Exception as e: # Skip, keep going. LOG.error("Cannot schedule email: %s" % (e.message, ))
def handle_email(self, session, author, subscribers, method, url, path, query_string, status, resource, resource_id, sub_resource=None, sub_resource_id=None, resource_before=None, resource_after=None): """Send an email for a specific event. We assume that filtering logic has already occurred when this method is invoked. :param session: An event-specific SQLAlchemy session. :param author: The author's user record. :param subscribers: A list of subscribers that should receive an email. :param method: The HTTP Method. :param url: The Referer header from the request. :param path: The full HTTP Path requested. :param query_string: The query string from the request. :param status: The returned HTTP Status of the response. :param resource: The resource type. :param resource_id: The ID of the resource. :param sub_resource: The subresource type. :param sub_resource_id: The ID of the subresource. :param resource_before: The resource state before this event occurred. :param resource_after: The resource state after this event occurred. """ email_config = CONF.plugin_email # Retrieve the template names. (subject_template, text_template, html_template) = \ self.get_templates(method=method, resource_name=resource, sub_resource_name=sub_resource) # Build our factory. If an HTML template exists, add it. If it can't # find the template, skip. try: factory = EmailFactory(sender=email_config.sender, subject=subject_template, text_template=text_template) except TemplateNotFound: LOG.error("Templates not found [%s, %s]" % (subject_template, text_template)) return # Try to add an HTML template try: factory.add_text_template(html_template, 'html') except TemplateNotFound: LOG.debug('Template %s not found' % (html_template,)) # If there's a reply-to in our config, add that. if email_config.reply_to: factory.add_header('Reply-To', email_config.reply_to) # Resolve the resource instance resource_instance = self.resolve_resource_by_name(session, resource, resource_id) sub_resource_instance = self.resolve_resource_by_name(session, sub_resource, sub_resource_id) # Figure out the diff between old and new. before, after = self.get_changed_properties(resource_before, resource_after) # For each subscriber, create the email and send it. with smtp.get_smtp_client() as smtp_client: for subscriber in subscribers: # Make sure this subscriber's preferences indicate they want # email and they're not receiving digests. if not self.get_preference('plugin_email_enable', subscriber) \ or self.get_preference('plugin_email_digest', subscriber): continue try: # Build an email. message = factory.build(recipient=subscriber.email, author=author, resource=resource_instance, sub_resource=sub_resource_instance, url=url, query_string=query_string, before=before, after=after) # Send the email. from_addr = message.get('From') to_addrs = message.get('To') try: smtp_client.sendmail(from_addr=from_addr, to_addrs=to_addrs, msg=message.as_string()) except smtplib.SMTPException as e: LOG.error('Cannot send email, discarding: %s' % (e,)) except Exception as e: # Skip, keep going. LOG.error("Cannot schedule email: %s" % (e.message,))