def test_delete_nonmembers_on_adding_member(self): # GL: #237 - When a new address is subscribed, any existing nonmember # subscriptions for this address; or any addresses also controlled by # this user, are deleted. anne_nonmember = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.nonmember) # Add a few other validated addresses to this user, and subscribe them # as nonmembers. for email in ('*****@*****.**', '*****@*****.**'): address = anne_nonmember.user.register(email) address.verified_on = now() self._mlist.subscribe(address, MemberRole.nonmember) # There are now three nonmembers. self.assertEqual( {address.email for address in self._mlist.nonmembers.addresses}, {'*****@*****.**', '*****@*****.**', '*****@*****.**', }) # Let's now add one of Anne's addresses as a member. This deletes all # of Anne's nonmember memberships. anne_member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.member) self.assertEqual(self._mlist.nonmembers.member_count, 0) members = list(self._mlist.members.members) self.assertEqual(len(members), 1) self.assertEqual(members[0], anne_member)
def test_add_member_with_mixed_case_email(self): # LP: #1425359 - Mailman is case-perserving, case-insensitive. This # test subscribes the lower case address and ensures the original # mixed case address can't be subscribed. email = '*****@*****.**' add_member( self._mlist, RequestRecord(email.lower(), 'Ann Person', DeliveryMode.regular, system_preferences.preferred_language)) with self.assertRaises(AlreadySubscribedError) as cm: add_member( self._mlist, RequestRecord(email, 'Ann Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual(cm.exception.email, email)
def test_action_munge_from_display_name_in_list(self): self._mlist.dmarc_mitigate_action = DMARCMitigateAction.munge_from add_member(self._mlist, RequestRecord('*****@*****.**', 'Anna Banana')) msgdata = {'dmarc': True} msg = mfs(self._text) dmarc.process(self._mlist, msg, msgdata) self.assertMultiLineEqual( msg.as_string(), """\ To: [email protected] Subject: A subject X-Mailman-Version: X.Y Message-ID: <*****@*****.**> Date: Fri, 1 Jan 2016 00:00:01 +0000 Another-Header: To test removal in wrapper MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=====abc==" From: Anna Banana via Ant <*****@*****.**> Reply-To: [email protected] --=====abc== Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Some things to say. --=====abc== Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: 7bit <html><head></head><body>Some things to say.</body></html> --=====abc==-- """)
def add_members(self, mlist, args): """Add the members in a file to a mailing list. :param mlist: The mailing list to operate on. :type mlist: `IMailingList` :param args: The command line arguments. :type args: `argparse.Namespace` """ with ExitStack() as resources: if args.input_filename == '-': fp = sys.stdin else: fp = resources.enter_context( open(args.input_filename, 'r', encoding='utf-8')) for line in fp: # Ignore blank lines and lines that start with a '#'. if line.startswith('#') or len(line.strip()) == 0: continue # Parse the line and ensure that the values are unicodes. display_name, email = parseaddr(line) try: add_member(mlist, RequestRecord(email, display_name, DeliveryMode.regular, mlist.preferred_language.code)) except AlreadySubscribedError: # It's okay if the address is already subscribed, just # print a warning and continue. if not display_name: print(_('Already subscribed (skipping): $email')) else: print(_('Already subscribed (skipping): ' '$display_name <$email>'))
def add_members(mlist, add_infp): for line in add_infp: # Ignore blank lines and lines that start with a '#'. if line.startswith('#') or len(line.strip()) == 0: continue # Parse the line and ensure that the values are unicodes. display_name, email = parseaddr(line) if email == '': line = line.strip() print(_('Cannot parse as valid email address (skipping): $line'), file=sys.stderr) continue try: add_member( mlist, RequestRecord(email, display_name, DeliveryMode.regular, mlist.preferred_language.code)) except InvalidEmailAddressError: # pragma: nocover # There is a test for this, but it hits the if email == '' above. # It's okay if the address is invalid, we print a warning and # continue. line = line.strip() print(_('Cannot parse as valid email address (skipping): $line'), file=sys.stderr) except AlreadySubscribedError: # It's okay if the address is already subscribed, just print a # warning and continue. if not display_name: print(_('Already subscribed (skipping): $email'), file=sys.stderr) else: print( _('Already subscribed (skipping): $display_name <$email>'), file=sys.stderr)
def test_add_member_globally_banned_by_pattern(self): # Addresses matching global regexp ban patterns cannot subscribe. IBanManager(None).ban('^.*@example.com') self.assertRaises( MembershipIsBannedError, add_member, self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language))
def test_add_posting_address(self): # Test that we can't add the list posting address. self.assertRaises( InvalidEmailAddressError, add_member, self._mlist, RequestRecord(self._mlist.posting_address, 'The List', DeliveryMode.regular, system_preferences.preferred_language))
def test_add_member_globally_banned(self): # Test that members who are banned by specific address cannot # subscribe to the mailing list. IBanManager(None).ban('*****@*****.**') self.assertRaises( MembershipIsBannedError, add_member, self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language))
def test_add_member_twice(self): # Adding a member with the same role twice causes an # AlreadySubscribedError to be raised. add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.member) with self.assertRaises(AlreadySubscribedError) as cm: add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.member) self.assertEqual(cm.exception.fqdn_listname, '*****@*****.**') self.assertEqual(cm.exception.email, '*****@*****.**') self.assertEqual(cm.exception.role, MemberRole.member)
def test_add_posting_address_nonmember(self): # Test that we can add the list posting address as a nonmember. request_record = RequestRecord(self._mlist.posting_address, 'The List', DeliveryMode.regular, system_preferences.preferred_language) member = add_member(self._mlist, request_record, MemberRole.nonmember) self.assertEqual(member.address.email, self._mlist.posting_address) self.assertEqual(member.list_id, 'test.example.com') self.assertEqual(member.role, MemberRole.nonmember)
def test_add_member_banned_from_different_list_by_pattern(self): # Addresses matching regexp ban patterns on one list can still # subscribe to other mailing lists. sample_list = create_list('*****@*****.**') IBanManager(sample_list).ban('^.*@example.com') member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual(member.address.email, '*****@*****.**')
def test_add_member_with_different_roles(self): # Adding a member twice with different roles is okay. member_1 = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.member) member_2 = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.owner) self.assertEqual(member_1.list_id, member_2.list_id) self.assertEqual(member_1.address, member_2.address) self.assertEqual(member_1.user, member_2.user) self.assertNotEqual(member_1.member_id, member_2.member_id) self.assertEqual(member_1.role, MemberRole.member) self.assertEqual(member_2.role, MemberRole.owner)
def test_add_member_moderator(self): # Test adding a moderator to a mailing list. member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language), MemberRole.moderator) self.assertEqual(member.address.email, '*****@*****.**') self.assertEqual(member.list_id, 'test.example.com') self.assertEqual(member.role, MemberRole.moderator)
def test_add_member_banned_from_different_list(self): # Test that members who are banned by on a different list can still be # subscribed to other mlists. sample_list = create_list('*****@*****.**') IBanManager(sample_list).ban('*****@*****.**') member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual(member.address.email, '*****@*****.**')
def test_add_member_new_user(self): # Test subscribing a user to a mailing list when the email address has # not yet been associated with a user. member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual(member.address.email, '*****@*****.**') self.assertEqual(member.list_id, 'test.example.com') self.assertEqual(member.role, MemberRole.member)
def test_add_member_existing_user(self): # Test subscribing a user to a mailing list when the email address has # already been associated with a user. user_manager = getUtility(IUserManager) user_manager.create_user('*****@*****.**', 'Anne Person') member = add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual(member.address.email, '*****@*****.**') self.assertEqual(member.list_id, 'test.example.com')
def test_add_member_banned(self): # Test that members who are banned by specific address cannot # subscribe to the mailing list. IBanManager(self._mlist).ban('*****@*****.**') with self.assertRaises(MembershipIsBannedError) as cm: add_member( self._mlist, RequestRecord('*****@*****.**', 'Anne Person', DeliveryMode.regular, system_preferences.preferred_language)) self.assertEqual( str(cm.exception), '[email protected] is not allowed to subscribe to [email protected]')
def add_members(mlist, infp): for line in infp: # Ignore blank lines and lines that start with a '#'. if line.startswith('#') or len(line.strip()) == 0: continue # Parse the line and ensure that the values are unicodes. display_name, email = parseaddr(line) try: add_member(mlist, RequestRecord(email, display_name, DeliveryMode.regular, mlist.preferred_language.code)) except AlreadySubscribedError: # It's okay if the address is already subscribed, just print a # warning and continue. if not display_name: print(_('Already subscribed (skipping): $email')) else: print(_('Already subscribed (skipping): ' '$display_name <$email>'))
def on_post(self, request, response): """Create a new member.""" try: validator = Validator(list_id=str, subscriber=subscriber_validator(self.api), display_name=str, delivery_mode=enum_validator(DeliveryMode), role=enum_validator(MemberRole), pre_verified=bool, pre_confirmed=bool, pre_approved=bool, _optional=('delivery_mode', 'display_name', 'role', 'pre_verified', 'pre_confirmed', 'pre_approved')) arguments = validator(request) except ValueError as error: bad_request(response, str(error)) return # Dig the mailing list out of the arguments. list_id = arguments.pop('list_id') mlist = getUtility(IListManager).get_by_list_id(list_id) if mlist is None: bad_request(response, b'No such list') return # Figure out what kind of subscriber is being registered. Either it's # a user via their preferred email address or it's an explicit address. # If it's a UUID, then it must be associated with an existing user. subscriber = arguments.pop('subscriber') user_manager = getUtility(IUserManager) # We use the display name if there is one. display_name = arguments.pop('display_name', '') if isinstance(subscriber, UUID): user = user_manager.get_user_by_id(subscriber) if user is None: bad_request(response, b'No such user') return subscriber = user else: # This must be an email address. See if there's an existing # address object associated with this email. address = user_manager.get_address(subscriber) if address is None: # Create a new address, which of course will not be validated. address = user_manager.create_address(subscriber, display_name) subscriber = address # What role are we subscribing? Regular members go through the # subscription policy workflow while owners, moderators, and # nonmembers go through the legacy API for now. role = arguments.pop('role', MemberRole.member) if role is MemberRole.member: # Get the pre_ flags for the subscription workflow. pre_verified = arguments.pop('pre_verified', False) pre_confirmed = arguments.pop('pre_confirmed', False) pre_approved = arguments.pop('pre_approved', False) # Now we can run the registration process until either the # subscriber is subscribed, or the workflow is paused for # verification, confirmation, or approval. registrar = ISubscriptionManager(mlist) try: token, token_owner, member = registrar.register( subscriber, pre_verified=pre_verified, pre_confirmed=pre_confirmed, pre_approved=pre_approved) except AlreadySubscribedError: conflict(response, b'Member already subscribed') return except MissingPreferredAddressError: bad_request(response, b'User has no preferred address') return except MembershipIsBannedError: bad_request(response, b'Membership is banned') return except SubscriptionPendingError: conflict(response, b'Subscription request already pending') return if token is None: assert token_owner is TokenOwner.no_one, token_owner # The subscription completed. Let's get the resulting member # and return the location to the new member. Member ids are # UUIDs and need to be converted to URLs because JSON doesn't # directly support UUIDs. member_id = self.api.from_uuid(member.member_id) location = self.api.path_to('members/{}'.format(member_id)) created(response, location) return # The member could not be directly subscribed because there are # some out-of-band steps that need to be completed. E.g. the user # must confirm their subscription or the moderator must approve # it. In this case, an HTTP 202 Accepted is exactly the code that # we should use, and we'll return both the confirmation token and # the "token owner" so the client knows who should confirm it. assert token is not None, token assert token_owner is not TokenOwner.no_one, token_owner assert member is None, member content = dict(token=token, token_owner=token_owner.name) accepted(response, etag(content)) return # 2015-04-15 BAW: We're subscribing some role other than a regular # member. Use the legacy API for this for now. assert role in (MemberRole.owner, MemberRole.moderator, MemberRole.nonmember) # 2015-04-15 BAW: We're limited to using an email address with this # legacy API, so if the subscriber is a user, the user must have a # preferred address, which we'll use, even though it will subscribe # the explicit address. It is an error if the user does not have a # preferred address. # # If the subscriber is an address object, just use that. if IUser.providedBy(subscriber): if subscriber.preferred_address is None: bad_request(response, b'User without preferred address') return email = subscriber.preferred_address.email else: assert IAddress.providedBy(subscriber) email = subscriber.email delivery_mode = arguments.pop('delivery_mode', DeliveryMode.regular) record = RequestRecord(email, display_name, delivery_mode) try: member = add_member(mlist, record, role) except MembershipIsBannedError: bad_request(response, b'Membership is banned') return except AlreadySubscribedError: bad_request( response, '{} is already an {} of {}'.format(email, role.name, mlist.fqdn_listname)) return # The subscription completed. Let's get the resulting member # and return the location to the new member. Member ids are # UUIDs and need to be converted to URLs because JSON doesn't # directly support UUIDs. member_id = self.api.from_uuid(member.member_id) location = self.api.path_to('members/{}'.format(member_id)) created(response, location)
def add(self, email): """Add email to mailinglist.""" add_member( self.list, RequestRecord(email, '', DeliveryMode.regular, self.list.preferred_language.code))