def test_non_persistent_message(self, send_email, render_to_string): render_to_string.return_value = 'Test' class TestNotification(SiteNotification): name = 'foo' success_message = 'Test success message' success_level = INFO_NON_PERSISTENT user = fixture.get(User) n = TestNotification(user, True) backend = SiteBackend(request=None) self.assertEqual(PersistentMessage.objects.count(), 0) backend.send(n) # No email is sent for non persistent messages send_email.assert_not_called() self.assertEqual(PersistentMessage.objects.count(), 1) self.assertEqual(PersistentMessage.objects.filter(read=False).count(), 1) self.client.force_login(user) response = self.client.get('/dashboard/') self.assertContains(response, 'Test success message') self.assertEqual(PersistentMessage.objects.count(), 1) self.assertEqual(PersistentMessage.objects.filter(read=True).count(), 1) response = self.client.get('/dashboard/') self.assertNotContains(response, 'Test success message')
def test_non_persistent_message(self, send_email, render_to_string): render_to_string.return_value = 'Test' class TestNotification(SiteNotification): name = 'foo' success_message = 'Test success message' success_level = INFO_NON_PERSISTENT user = fixture.get(User) # Setting the primary and verified email address of the user email = fixture.get(EmailAddress, user=user, primary=True, verified=True) n = TestNotification(user, True) backend = SiteBackend(request=None) self.assertEqual(PersistentMessage.objects.count(), 0) backend.send(n) # No email is sent for non persistent messages send_email.assert_not_called() self.assertEqual(PersistentMessage.objects.count(), 1) self.assertEqual( PersistentMessage.objects.filter(read=False).count(), 1) self.client.force_login(user) response = self.client.get('/dashboard/') self.assertContains(response, 'Test success message') self.assertEqual(PersistentMessage.objects.count(), 1) self.assertEqual( PersistentMessage.objects.filter(read=True).count(), 1) response = self.client.get('/dashboard/') self.assertNotContains(response, 'Test success message')
def test_email_backend(self, add_message, render_to_string): class TestNotification(Notification): name = 'foo' subject = 'This is {{ foo.id }}' context_object_name = 'foo' build = fixture.get(Build) req = mock.MagicMock() notify = TestNotification(object=build, request=req) backend = SiteBackend(request=req) backend.send(notify) add_message.assert_has_calls([ mock.call(level=21, request=req, message=mock.ANY, extra_tags='') ])
def test_email_backend(self, add_message, render_to_string): class TestNotification(Notification): name = 'foo' subject = 'This is {{ foo.id }}' context_object_name = 'foo' build = fixture.get(Build) user = fixture.get(User) req = mock.MagicMock() notify = TestNotification(object=build, request=req, user=user) backend = SiteBackend(request=req) backend.send(notify) add_message.assert_has_calls([ mock.call(level=21, request=req, message=mock.ANY, extra_tags='', user=user) ])
def test_message_backend(self, render_to_string): render_to_string.return_value = 'Test' class TestNotification(Notification): name = 'foo' subject = 'This is {{ foo.id }}' context_object_name = 'foo' build = fixture.get(Build) user = fixture.get(User) req = mock.MagicMock() notify = TestNotification(context_object=build, request=req, user=user) backend = SiteBackend(request=req) backend.send(notify) self.assertEqual(render_to_string.call_count, 1) self.assertEqual(PersistentMessage.objects.count(), 1) message = PersistentMessage.objects.first() self.assertEqual(message.user, user)
def test_message_anonymous_user(self, render_to_string): """Anonymous user still throwns exception on persistent messages.""" render_to_string.return_value = 'Test' class TestNotification(Notification): name = 'foo' subject = 'This is {{ foo.id }}' context_object_name = 'foo' build = fixture.get(Build) user = AnonymousUser() req = mock.MagicMock() notify = TestNotification(context_object=build, request=req, user=user) backend = SiteBackend(request=req) self.assertEqual(PersistentMessage.objects.count(), 0) # We should never be adding persistent messages for anonymous users. # Make sure message_extends sitll throws an exception here with self.assertRaises(NotImplementedError): backend.send(notify) self.assertEqual(render_to_string.call_count, 1) self.assertEqual(PersistentMessage.objects.count(), 0)
def test_message_anonymous_user(self, render_to_string): """Anonymous user still throwns exception on persistent messages""" render_to_string.return_value = 'Test' class TestNotification(Notification): name = 'foo' subject = 'This is {{ foo.id }}' context_object_name = 'foo' build = fixture.get(Build) user = AnonymousUser() req = mock.MagicMock() notify = TestNotification(context_object=build, request=req, user=user) backend = SiteBackend(request=req) self.assertEqual(PersistentMessage.objects.count(), 0) # We should never be adding persistent messages for anonymous users. # Make sure message_extends sitll throws an exception here with self.assertRaises(NotImplementedError): backend.send(notify) self.assertEqual(render_to_string.call_count, 1) self.assertEqual(PersistentMessage.objects.count(), 0)
def contact_users( users, email_subject=None, email_content=None, from_email=None, notification_content=None, sticky_notification=False, context_function=None, dryrun=True, ): """ Send an email or a sticky notification to a list of users. :param users: Queryset of Users. :param string email_subject: Email subject :param string email_content: Email content (markdown) :param string from_email: Email to sent from (Test Support <*****@*****.**>) :param string notification_content: Content for the sticky notification (markdown) :param context_function: A callable that will receive an user and return a dict of additional context to be used in the email/notification content :param bool dryrun: If `True` don't sent the email or notification, just print the content The `email_content` and `notification_content` contents will be rendered using a template with the following context:: { 'user': <user object>, 'domain': https://readthedocs.org, } :returns: A dictionary with a list of sent/failed emails/notifications. """ from_email = from_email or settings.DEFAULT_FROM_EMAIL context_function = context_function or (lambda user: {}) sent_emails = set() failed_emails = set() sent_notifications = set() failed_notifications = set() backend = SiteBackend(request=None) engine = Engine.get_default() notification_template = engine.from_string(notification_content or '') email_template = engine.from_string(email_content or '') email_txt_template = engine.get_template('core/email/common.txt') email_html_template = engine.get_template('core/email/common.html') class TempNotification(SiteNotification): if sticky_notification: success_level = message_constants.SUCCESS_PERSISTENT def render(self, *args, **kwargs): context = { 'user': self.user, 'domain': f'https://{settings.PRODUCTION_DOMAIN}', } context.update(context_function(self.user)) return markdown.markdown( notification_template.render(Context(context))) total = users.count() for count, user in enumerate(users.iterator(), start=1): context = { 'user': user, 'domain': f'https://{settings.PRODUCTION_DOMAIN}', } context.update(context_function(user)) if notification_content: notification = TempNotification( user=user, success=True, ) try: if not dryrun: backend.send(notification) else: pprint( markdown.markdown( notification_template.render(Context(context)))) except Exception: log.exception('Notification failed to send') failed_notifications.add(user.username) else: log.info( 'Successfully set notification.', user_username=user.username, count=count, total=total, ) sent_notifications.add(user.username) if email_subject: emails = list( user.emailaddress_set.filter(verified=True).exclude( email=user.email).values_list('email', flat=True)) emails.append(user.email) # First render the markdown context. email_txt_content = email_template.render(Context(context)) email_html_content = markdown.markdown(email_txt_content) # Now render it using the base email templates. email_txt_rendered = email_txt_template.render( Context({'content': email_txt_content})) email_html_rendered = email_html_template.render( Context({'content': email_html_content})) try: kwargs = dict( subject=email_subject, message=email_txt_rendered, html_message=email_html_rendered, from_email=from_email, recipient_list=emails, ) if not dryrun: send_mail(**kwargs) else: pprint(kwargs) except Exception: log.exception('Email failed to send') failed_emails.update(emails) else: log.info('Email sent.', emails=emails, count=count, total=total) sent_emails.update(emails) return { 'email': { 'sent': sent_emails, 'failed': failed_emails, }, 'notification': { 'sent': sent_notifications, 'failed': failed_emails, }, }
def contact_users( users, email_subject=None, email_content=None, email_content_html=None, from_email=None, notification_content=None, dryrun=True, ): """ Send an email or a sticky notification to a list of users. :param users: Queryset of Users. :param string email_subject: Email subject :param string email_content: Email content (txt) :param string email_content_html: Email content (HTML) :param string from_email: Email to sent from (Test Support <*****@*****.**>) :param string notification_content: Content for the sticky notification. :param bool dryrun: If `True` don't sent the email or notification, just print the content. :returns: A dictionary with a list of sent/failed emails/notifications. """ from_email = from_email or settings.DEFAULT_FROM_EMAIL sent_emails = set() failed_emails = set() sent_notifications = set() failed_notifications = set() backend = SiteBackend(request=None) class TempNotification(SiteNotification): def render(self, *args, **kwargs): return notification_content for user in users.iterator(): if notification_content: notification = TempNotification( user=user, success=True, ) try: if not dryrun: backend.send(notification) else: pprint(notification_content) except Exception: log.exception('Notification failed to send') failed_notifications.add(user.pk) else: log.info('Successfully set notification user=%s', user) sent_notifications.add(user.pk) if email_subject: emails = list( user.emailaddress_set .filter(verified=True) .exclude(email=user.email) .values_list('email', flat=True) ) emails.append(user.email) try: kwargs = dict( subject=email_subject, message=email_content, html_message=email_content_html, from_email=from_email, recipient_list=emails, ) if not dryrun: send_mail(**kwargs) else: pprint(kwargs) except Exception: log.exception('Mail failed to send') failed_emails.update(emails) else: log.info('Email sent to %s', emails) sent_emails.update(emails) return { 'email': { 'sent': sent_emails, 'failed': failed_emails, }, 'notification': { 'sent': sent_notifications, 'failed': failed_emails, }, }