def test_recipients_to_addresses_with_groups_and_users(self): """Testing generating addresses from recipients that are users and groups with mailing list addresses """ groups = [ Group(name='group1', display_name='Group One', mailing_list='*****@*****.**'), Group(name='group2', display_name='Group Two', mailing_list='*****@*****.**'), ] users = list(User.objects.filter(username__in=['doc', 'grumpy']).all()) addresses = recipients_to_addresses(groups + users) self.assertEqual(len(addresses), 4) user_addresses = [ build_email_address_for_user(u) for u in users ] group_addresses = sum( ( get_email_addresses_for_group(group) for group in groups ), []) self.assertEqual(addresses, set(user_addresses + group_addresses))
def test_recipients_to_addresses_with_groups_with_members(self): """Testing generating addresses from recipients that are groups with no mailing list addresses """ group1 = Group.objects.create(name='group1') group2 = Group.objects.create(name='group2') user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create_user(username='******', first_name='User', last_name='Two', email='*****@*****.**') group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) expected_addresses = set([ build_email_address_for_user(user1), build_email_address_for_user(user2), ]) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_groups_local_site_inactive_members(self): """Testing generating addresses from recipients that are groups in local sites that have inactive members """ local_site1 = LocalSite.objects.create(name='local-site1') local_site2 = LocalSite.objects.create(name='local-site2') group1 = self.create_review_group('group1', local_site=local_site1) group2 = self.create_review_group('group2', local_site=local_site2) user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create(username='******', first_name='User', last_name='Two', is_active=False, email='*****@*****.**') local_site1.users = [user1] local_site2.users = [user2] group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) self.assertEqual(len(addresses), 1) self.assertEqual(addresses, set([build_email_address_for_user(user1)]))
def test_recipients_to_addresses_groups_local_site_inactive_members(self): """Testing generating addresses from recipients that are groups in local sites that have inactive members """ local_site1 = LocalSite.objects.create(name='local-site1') local_site2 = LocalSite.objects.create(name='local-site2') group1 = self.create_review_group('group1', local_site=local_site1) group2 = self.create_review_group('group2', local_site=local_site2) user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create(username='******', first_name='User', last_name='Two', is_active=False, email='*****@*****.**') local_site1.users = [user1] local_site2.users = [user2] group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) self.assertEqual(len(addresses), 1) self.assertEqual(addresses, set([build_email_address_for_user(user1)]))
def test_recipients_to_addresses_with_groups_with_members(self): """Testing generating addresses from recipients that are groups with no mailing list addresses """ group1 = Group.objects.create(name='group1') group2 = Group.objects.create(name='group2') user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create_user(username='******', first_name='User', last_name='Two', email='*****@*****.**') group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) expected_addresses = set([ build_email_address_for_user(user1), build_email_address_for_user(user2), ]) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_with_users(self): """Testing generating addresses from recipients with user recipients """ users = list(User.objects.filter(username__in=['doc', 'grumpy'])) addresses = recipients_to_addresses(users) self.assertEqual(len(addresses), 2) expected_addresses = set( build_email_address_for_user(u) for u in users) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_with_users(self): """Testing generating addresses from recipients with user recipients """ users = list(User.objects.filter(username__in=['doc', 'grumpy'])) addresses = recipients_to_addresses(users) self.assertEqual(len(addresses), 2) expected_addresses = set( build_email_address_for_user(u) for u in users ) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_with_groups_inactive_members(self): """Testing generating addresses form recipients that are groups with inactive members """ group1 = self.create_review_group('group1') group2 = self.create_review_group('group2') user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create(username='******', first_name='User', last_name='Two', is_active=False, email='*****@*****.**') group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) self.assertEqual(len(addresses), 1) self.assertEqual(addresses, set([build_email_address_for_user(user1)]))
def test_recipients_to_addresses_with_groups_many_mailinglist(self): """Testing generating addresses from recipients that are groups with multiple mailing list addresses """ groups = [ Group(name='group1', display_name='Group One', mailing_list='[email protected],[email protected]'), Group(name='group2', display_name='Group Two', mailing_list='[email protected],[email protected]'), ] addresses = recipients_to_addresses(groups) self.assertEqual(len(addresses), 4) expected_addresses = set( sum((get_email_addresses_for_group(group) for group in groups), [])) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_with_groups_many_mailinglist(self): """Testing generating addresses from recipients that are groups with multiple mailing list addresses """ groups = [ Group(name='group1', display_name='Group One', mailing_list='[email protected],[email protected]'), Group(name='group2', display_name='Group Two', mailing_list='[email protected],[email protected]'), ] addresses = recipients_to_addresses(groups) self.assertEqual(len(addresses), 4) expected_addresses = set(sum( ( get_email_addresses_for_group(group) for group in groups ), [])) self.assertEqual(addresses, expected_addresses)
def test_recipients_to_addresses_with_groups_inactive_members(self): """Testing generating addresses form recipients that are groups with inactive members """ group1 = self.create_review_group('group1') group2 = self.create_review_group('group2') user1 = User.objects.create_user(username='******', first_name='User', last_name='One', email='*****@*****.**') user2 = User.objects.create(username='******', first_name='User', last_name='Two', is_active=False, email='*****@*****.**') group1.users = [user1] group2.users = [user2] addresses = recipients_to_addresses([group1, group2]) self.assertEqual(len(addresses), 1) self.assertEqual(addresses, set([build_email_address_for_user(user1)]))
def test_recipients_to_addresses_with_groups_and_users(self): """Testing generating addresses from recipients that are users and groups with mailing list addresses """ groups = [ Group(name='group1', display_name='Group One', mailing_list='*****@*****.**'), Group(name='group2', display_name='Group Two', mailing_list='*****@*****.**'), ] users = list(User.objects.filter(username__in=['doc', 'grumpy']).all()) addresses = recipients_to_addresses(groups + users) self.assertEqual(len(addresses), 4) user_addresses = [build_email_address_for_user(u) for u in users] group_addresses = sum( (get_email_addresses_for_group(group) for group in groups), []) self.assertEqual(addresses, set(user_addresses + group_addresses))
def prepare_base_review_request_mail(user, review_request, subject, in_reply_to, to_field, cc_field, template_name_base, context=None, extra_headers=None): """Return a customized review request e-mail. This is intended to be called by one of the ``prepare_{type}_mail`` functions in this file. This method builds up a common context that all review request-related e-mails will use to render their templates, as well as handling user preferences regarding e-mail and add adding additional headers. Args: user (django.contrib.auth.models.User): The user who is sending the e-mail. review_request (reviewboard.reviews.models.review_request.ReviewRequest): The review request this e-mail is regarding. subject (unicode): The e-mail subject line. in_reply_to (unicode): The e-mail message ID this message is in response to or ``None``. to_field (set): The set of :py:class:`~django.contrib.auth.models.User` and :py:class`~reviewboard.reviews.models.group.Group`s to this e-mail will be sent to. cc_field (set): The set of :py:class:`~django.contrib.auth.models.User` and :py:class`~reviewboard.reviews.models.group.Group`s to be CC'ed on the e-mail. template_name_base (unicode): The name of the template to use to generate the e-mail without its extension. The plain-text version of the e-mail will append ``.txt`` to this and and the rich-text version of the e-mail will append ``.html``. context (dict, optional): Optional additional template rendering context. extra_headers (dict, optional): Optional additional headers to include. Returns: EmailMessage: The prepared e-mail message. """ user_email = build_email_address_for_user(user) to_field = recipients_to_addresses(to_field, review_request.id) cc_field = recipients_to_addresses(cc_field, review_request.id) - to_field if not user.should_send_own_updates(): to_field.discard(user_email) cc_field.discard(user_email) if not to_field and not cc_field: # This e-mail would have no recipients, so we won't send it. return None if not context: context = {} context.update({ 'user': user, 'site_url': get_server_url(), 'review_request': review_request, }) local_site = review_request.local_site if local_site: context['local_site_name'] = local_site.name text_body = render_to_string('%s.txt' % template_name_base, context) html_body = render_to_string('%s.html' % template_name_base, context) server_url = get_server_url(local_site=local_site) headers = MultiValueDict({ 'X-ReviewBoard-URL': [server_url], 'X-ReviewRequest-URL': [ build_server_url(review_request.get_absolute_url(), local_site=local_site) ], 'X-ReviewGroup': [ ', '.join( review_request.target_groups.values_list('name', flat=True)) ], }) if extra_headers: if not isinstance(extra_headers, MultiValueDict): extra_headers = MultiValueDict( (key, [value]) for key, value in six.iteritems(extra_headers)) headers.update(extra_headers) if review_request.repository: headers['X-ReviewRequest-Repository'] = review_request.repository.name latest_diffset = review_request.get_latest_diffset() if latest_diffset: modified_files = set() for filediff in latest_diffset.files.all(): if filediff.deleted or filediff.copied or filediff.moved: modified_files.add(filediff.source_file) if filediff.is_new or filediff.copied or filediff.moved: modified_files.add(filediff.dest_file) # The following code segment deals with the case where the client adds # a significant amount of files with large names. We limit the number # of headers; when more than 8192 characters are reached, we stop # adding filename headers. current_header_length = 0 for filename in modified_files: current_header_length += (HEADER_ADDITIONAL_CHARACTERS_LENGTH + len(filename)) if current_header_length > MAX_FILENAME_HEADERS_LENGTH: logging.warning( 'Unable to store all filenames in the ' 'X-ReviewBoard-Diff-For headers when sending e-mail for ' 'review request %s: The header size exceeds the limit of ' '%s. Remaining headers have been omitted.', review_request.display_id, MAX_FILENAME_HEADERS_LENGTH) break headers.appendlist('X-ReviewBoard-Diff-For', filename) if settings.DEFAULT_FROM_EMAIL: sender = build_email_address(full_name=user.get_full_name(), email=settings.DEFAULT_FROM_EMAIL) else: sender = None return EmailMessage(subject=subject.strip(), text_body=text_body.encode('utf-8'), html_body=html_body.encode('utf-8'), from_email=user_email, sender=sender, to=list(to_field), cc=list(cc_field), in_reply_to=in_reply_to, headers=headers)
def prepare_base_review_request_mail(user, review_request, subject, in_reply_to, to_field, cc_field, template_name_base, context=None, extra_headers=None): """Return a customized review request e-mail. This is intended to be called by one of the ``prepare_{type}_mail`` functions in this file. This method builds up a common context that all review request-related e-mails will use to render their templates, as well as handling user preferences regarding e-mail and add adding additional headers. Args: user (django.contrib.auth.models.User): The user who is sending the e-mail. review_request (reviewboard.reviews.models.review_request.ReviewRequest): The review request this e-mail is regarding. subject (unicode): The e-mail subject line. in_reply_to (unicode): The e-mail message ID this message is in response to or ``None``. to_field (set): The set of :py:class:`~django.contrib.auth.models.User` and :py:class`~reviewboard.reviews.models.group.Group`s to this e-mail will be sent to. cc_field (set): The set of :py:class:`~django.contrib.auth.models.User` and :py:class`~reviewboard.reviews.models.group.Group`s to be CC'ed on the e-mail. template_name_base (unicode): The name of the template to use to generate the e-mail without its extension. The plain-text version of the e-mail will append ``.txt`` to this and and the rich-text version of the e-mail will append ``.html``. context (dict, optional): Optional additional template rendering context. extra_headers (dict, optional): Optional additional headers to include. Returns: EmailMessage: The prepared e-mail message. """ user_email = build_email_address_for_user(user) to_field = recipients_to_addresses(to_field, review_request.id) cc_field = recipients_to_addresses(cc_field, review_request.id) - to_field if not user.should_send_own_updates(): to_field.discard(user_email) cc_field.discard(user_email) if not to_field and not cc_field: # This e-mail would have no recipients, so we won't send it. return None if not context: context = {} context.update({ 'user': user, 'site_url': _get_server_base_url(), 'review_request': review_request, }) local_site = review_request.local_site if local_site: context['local_site_name'] = local_site.name text_body = render_to_string('%s.txt' % template_name_base, context) html_body = render_to_string('%s.html' % template_name_base, context) server_url = get_server_url(local_site=local_site) headers = MultiValueDict({ 'X-ReviewBoard-URL': [server_url], 'X-ReviewRequest-URL': [ build_server_url(review_request.get_absolute_url(), local_site=local_site) ], 'X-ReviewGroup': [', '.join( review_request.target_groups.values_list('name', flat=True) )], }) if extra_headers: if not isinstance(extra_headers, MultiValueDict): extra_headers = MultiValueDict( (key, [value]) for key, value in six.iteritems(extra_headers) ) headers.update(extra_headers) if review_request.repository: headers['X-ReviewRequest-Repository'] = review_request.repository.name latest_diffset = review_request.get_latest_diffset() if latest_diffset: modified_files = set() for filediff in latest_diffset.files.all(): if not filediff.is_new: modified_files.add(filediff.source_file) if not filediff.deleted: modified_files.add(filediff.dest_file) # The following code segment deals with the case where the client adds # a significant amount of files with large names. We limit the number # of headers; when more than 8192 characters are reached, we stop # adding filename headers. current_header_length = 0 for filename in modified_files: current_header_length += (HEADER_ADDITIONAL_CHARACTERS_LENGTH + len(filename)) if current_header_length > MAX_FILENAME_HEADERS_LENGTH: logging.warning( 'Unable to store all filenames in the ' 'X-ReviewBoard-Diff-For headers when sending e-mail for ' 'review request %s: The header size exceeds the limit of ' '%s. Remaining headers have been omitted.', review_request.display_id, MAX_FILENAME_HEADERS_LENGTH) break headers.appendlist('X-ReviewBoard-Diff-For', filename) if settings.DEFAULT_FROM_EMAIL: sender = build_email_address(full_name=user.get_full_name(), email=settings.DEFAULT_FROM_EMAIL) else: sender = None return EmailMessage(subject=subject.strip(), text_body=text_body.encode('utf-8'), html_body=html_body.encode('utf-8'), from_email=user_email, sender=sender, to=list(to_field), cc=list(cc_field), in_reply_to=in_reply_to, headers=headers)
def test_recipients_to_addresses_with_string_address(self): """Testing generating addresses from recipients with string recipients """ with self.assertRaises(AssertionError): recipients_to_addresses(['*****@*****.**'])
def test_recipients_to_addresses_with_string_address(self): """Testing generating addresses from recipients with string recipients """ with self.assertRaises(AssertionError): recipients_to_addresses(['*****@*****.**'])