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 test_add_member_with_different_roles(self): # Adding a member twice with different roles is okay. member_1 = add_member( self._mlist, "*****@*****.**", "Anne Person", "123", DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member, ) member_2 = add_member( self._mlist, "*****@*****.**", "Anne Person", "123", 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_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 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` """ if args.input_filename == "-": fp = sys.stdin else: fp = codecs.open(args.input_filename, "r", "utf-8") try: 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. print("Already subscribed (skipping):", email, display_name) finally: if fp is not sys.stdin: fp.close()
def test_add_member_twice(self): # Adding a member with the same role twice causes an # AlreadySubscribedError to be raised. add_member( self._mlist, "*****@*****.**", "Anne Person", "123", DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member, ) with self.assertRaises(AlreadySubscribedError) as cm: add_member( self._mlist, "*****@*****.**", "Anne Person", "123", 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 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` """ if args.input_filename == '-': fp = sys.stdin else: fp = codecs.open(args.input_filename, 'r', 'utf-8') try: 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) display_name = display_name.decode(fp.encoding) email = email.decode(fp.encoding) # Give the user a default, user-friendly password. password = generate(int(config.passwords.password_length)) try: add_member(mlist, email, display_name, password, DeliveryMode.regular, mlist.preferred_language.code) except AlreadySubscribedError: # It's okay if the address is already subscribed, just # print a warning and continue. print('Already subscribed (skipping):', email, display_name) finally: if fp is not sys.stdin: fp.close()
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, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual( str(cm.exception), '[email protected] is not allowed to subscribe to [email protected]')
def test_add_member_with_lower_case_email(self): # LP: #1425359 - Mailman is case-perserving, case-insensitive. This # test subscribes the mixed case address and ensures the lower cased # address can't be added. email = "*****@*****.**" add_member( self._mlist, RequestRecord(email, "Ann Person", DeliveryMode.regular, system_preferences.preferred_language) ) with self.assertRaises(AlreadySubscribedError) as cm: add_member( self._mlist, RequestRecord(email.lower(), "Ann Person", DeliveryMode.regular, system_preferences.preferred_language), ) self.assertEqual(cm.exception.email, email.lower())
def test_more_specific_welcome_message_nonenglish(self): # mlist.welcome_message_uri can contain placeholders for the fqdn list # name and language. self._mlist.welcome_message_uri = "mailman:///$listname/$language/welcome.txt" # Add the xx language and subscribe Anne using it. manager = getUtility(ILanguageManager) xx = manager.add("xx", "us-ascii", "Xlandia") add_member(self._mlist, "*****@*****.**", "Anne Person", "password", DeliveryMode.regular, "xx") send_welcome_message(self._mlist, "*****@*****.**", xx, DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages("virgin") self.assertEqual(len(messages), 1) message = messages[0].msg self.assertEqual(str(message["subject"]), 'Welcome to the "Test List" mailing list') self.assertEqual(message.get_payload(), "You just joined the Test List mailing list!")
def setUp(self): self._mlist = create_list('*****@*****.**') self._member = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'xxx', DeliveryMode.regular, 'en') self._msg = mfs("""\ From: [email protected] To: [email protected] Subject: You bounced Message-ID: <first> """) # Set up the translation context. self._var_dir = tempfile.mkdtemp() xx_template_path = os.path.join( self._var_dir, 'templates', 'site', 'xx', 'probe.txt') os.makedirs(os.path.dirname(xx_template_path)) config.push('xx template dir', """\ [paths.testing] var_dir: {0} """.format(self._var_dir)) language_manager = getUtility(ILanguageManager) language_manager.add('xx', 'utf-8', 'Freedonia') self._member.preferences.preferred_language = 'xx' with open(xx_template_path, 'w') as fp: print("""\ blah blah blah $listname $address $optionsurl $owneraddr """, file=fp) # Let assertMultiLineEqual work without bounds. self.maxDiff = None
def join(self, fqdn_listname, subscriber, display_name=None, delivery_mode=DeliveryMode.regular, role=MemberRole.member): """See `ISubscriptionService`.""" mlist = getUtility(IListManager).get(fqdn_listname) if mlist is None: raise NoSuchListError(fqdn_listname) # Is the subscriber an email address or user id? if isinstance(subscriber, basestring): # It's an email address, so we'll want a real name. Make sure # it's a valid email address, and let InvalidEmailAddressError # propagate up. getUtility(IEmailValidator).validate(subscriber) if display_name is None: display_name, at, domain = subscriber.partition('@') # Because we want to keep the REST API simple, there is no # password or language given to us. We'll use the system's # default language for the user's default language. We'll set the # password to a system default. This will have to get reset since # it can't be retrieved. Note that none of these are used unless # the address is completely new to us. password = generate(int(config.passwords.password_length)) return add_member(mlist, subscriber, display_name, password, delivery_mode, system_preferences.preferred_language, role) else: # We have to assume it's a UUID. assert isinstance(subscriber, UUID), 'Not a UUID' user = getUtility(IUserManager).get_user_by_id(subscriber) if user is None: raise MissingUserError(subscriber) return mlist.subscribe(user, role)
def setUp(self): self._mlist = create_list('*****@*****.**') self._mlist.personalize = Personalization.individual # Make Anne a member of this mailing list. self._anne = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'xyz', DeliveryMode.regular, 'en') # Clear out any results from the previous test. del _deliveries[:] self._msg = mfs("""\ From: [email protected] To: [email protected] Subject: test """) # Set up a personalized footer for decoration. self._template_dir = tempfile.mkdtemp() path = os.path.join(self._template_dir, 'site', 'en', 'member-footer.txt') os.makedirs(os.path.dirname(path)) with open(path, 'w') as fp: print("""\ address : $user_address delivered: $user_delivered_to language : $user_language name : $user_name options : $user_optionsurl """, file=fp) config.push('templates', """ [paths.testing] template_dir: {0} """.format(self._template_dir)) self._mlist.footer_uri = 'mailman:///member-footer.txt' # Let assertMultiLineEqual work without bounds. self.maxDiff = None
def test_add_member_password(self): # Test that the password stored with the new user is encrypted. member = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'abc', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual( member.user.password, '{SHA}qZk-NkcGgWq6PiVxeFDCbJzQ2J0=')
def test_add_member_banned_from_different_list(self): # Test that members who are banned by specific address cannot # subscribe to the mailing list. getUtility(IBanManager).ban('*****@*****.**', '*****@*****.**') member = add_member(self._mlist, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.address.email, '*****@*****.**')
def test_add_member_moderator(self): # Test adding a moderator to a mailing list. member = add_member(self._mlist, '*****@*****.**', 'Anne Person', '123', 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_twice(self): # Adding a member with the same role twice causes an # AlreadySubscribedError to be raised. add_member(self._mlist, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member) try: add_member(self._mlist, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language, MemberRole.member) except AlreadySubscribedError as exc: self.assertEqual(exc.fqdn_listname, '*****@*****.**') self.assertEqual(exc.email, '*****@*****.**') self.assertEqual(exc.role, MemberRole.member) else: raise AssertionError('AlreadySubscribedError expected')
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, '*****@*****.**', 'Anne Person', '123', 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_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, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.address.email, '*****@*****.**')
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, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.address.email, '*****@*****.**')
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, '*****@*****.**', 'Anne Person', '123', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.address.email, '*****@*****.**') self.assertEqual(member.list_id, 'test.example.com')
def handle_subscription(mlist, id, action, comment=None): requestdb = IListRequests(mlist) if action is Action.defer: # Nothing to do. return elif action is Action.discard: # Nothing to do except delete the request from the database. pass elif action is Action.reject: key, data = requestdb.get_request(id) _refuse(mlist, _('Subscription request'), data['address'], comment or _('[No reason given]'), lang=getUtility(ILanguageManager)[data['language']]) elif action is Action.accept: key, data = requestdb.get_request(id) enum_value = data['delivery_mode'].split('.')[-1] delivery_mode = DeliveryMode(enum_value) address = data['address'] display_name = data['display_name'] language = getUtility(ILanguageManager)[data['language']] password = data['password'] try: add_member(mlist, address, display_name, password, delivery_mode, language) except AlreadySubscribedError: # The address got subscribed in some other way after the original # request was made and accepted. pass else: if mlist.send_welcome_message: send_welcome_message(mlist, address, language, delivery_mode) if mlist.admin_notify_mchanges: send_admin_subscription_notice( mlist, address, display_name, language) slog.info('%s: new %s, %s %s', mlist.fqdn_listname, delivery_mode, formataddr((display_name, address)), 'via admin approval') else: raise AssertionError('Unexpected action: {0}'.format(action)) # Delete the request from the database. requestdb.delete_request(id)
def test_add_member_password(self): # Test that the password stored with the new user is encrypted. member = add_member( self._mlist, "*****@*****.**", "Anne Person", "abc", DeliveryMode.regular, system_preferences.preferred_language, ) self.assertEqual(member.user.password, "{plaintext}abc")
def test_more_specific_welcome_message_nonenglish(self): # mlist.welcome_message_uri can contain placeholders for the fqdn list # name and language. self._mlist.welcome_message_uri = ( 'mailman:///$listname/$language/welcome.txt') # Add the xx language and subscribe Anne using it. manager = getUtility(ILanguageManager) xx = manager.add('xx', 'us-ascii', 'Xlandia') add_member(self._mlist, '*****@*****.**', 'Anne Person', 'password', DeliveryMode.regular, 'xx') send_welcome_message(self._mlist, '*****@*****.**', xx, DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages('virgin') self.assertEqual(len(messages), 1) message = messages[0].msg self.assertEqual(str(message['subject']), 'Welcome to the "Test List" mailing list') self.assertEqual(message.get_payload(), 'You just joined the Test List mailing list!')
def setUp(self): self._mlist = create_list('*****@*****.**') self._member = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'xxx', DeliveryMode.regular, 'en') self._msg = mfs("""\ From: [email protected] To: [email protected] Subject: You bounced Message-ID: <first> """)
def test_welcome_message(self): en = getUtility(ILanguageManager).get('en') add_member(self._mlist, '*****@*****.**', 'Anne Person', 'password', DeliveryMode.regular, 'en') send_welcome_message(self._mlist, '*****@*****.**', en, DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages('virgin') self.assertEqual(len(messages), 1) message = messages[0].msg self.assertEqual(str(message['subject']), 'Welcome to the "Test List" mailing list') self.assertMultiLineEqual(message.get_payload(), """\ Welcome to the Test List mailing list. Posting address: [email protected] Help and other requests: [email protected] Your name: Anne Person Your address: [email protected] Your options: http://example.com/[email protected] """)
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_welcome_message(self): en = getUtility(ILanguageManager).get("en") add_member(self._mlist, "*****@*****.**", "Anne Person", "password", DeliveryMode.regular, "en") send_welcome_message(self._mlist, "*****@*****.**", en, DeliveryMode.regular) # Now there's one message in the virgin queue. messages = get_queue_messages("virgin") self.assertEqual(len(messages), 1) message = messages[0].msg self.assertEqual(str(message["subject"]), 'Welcome to the "Test List" mailing list') self.eq( message.get_payload(), """\ Welcome to the Test List mailing list. Posting address: [email protected] Help and other requests: [email protected] Your name: Anne Person Your address: [email protected] Your options: http://example.com/[email protected] """, )
def handle_subscription(mlist, id, action, comment=None): requestdb = IListRequests(mlist) if action is Action.defer: # Nothing to do. return elif action is Action.discard: # Nothing to do except delete the request from the database. pass elif action is Action.reject: key, data = requestdb.get_request(id) _refuse(mlist, _('Subscription request'), data['address'], comment or _('[No reason given]'), lang=getUtility(ILanguageManager)[data['language']]) elif action is Action.accept: key, data = requestdb.get_request(id) delivery_mode = DeliveryMode[data['delivery_mode']] address = data['address'] display_name = data['display_name'] language = getUtility(ILanguageManager)[data['language']] password = data['password'] try: add_member(mlist, address, display_name, password, delivery_mode, language) except AlreadySubscribedError: # The address got subscribed in some other way after the original # request was made and accepted. pass else: if mlist.admin_notify_mchanges: send_admin_subscription_notice(mlist, address, display_name, language) slog.info('%s: new %s, %s %s', mlist.fqdn_listname, delivery_mode, formataddr((display_name, address)), 'via admin approval') else: raise AssertionError('Unexpected action: {0}'.format(action)) # Delete the request from the database. requestdb.delete_request(id)
def setUp(self): self._mlist = create_list('*****@*****.**') self._mlist.send_welcome_message = False self._member = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'xxx', DeliveryMode.regular, 'en') self._msg = mfs("""\ From: [email protected] To: [email protected] Subject: You bounced Message-ID: <first> """)
def handle_subscription(mlist, id, action, comment=None): requestdb = IListRequests(mlist) if action is Action.defer: # Nothing to do. return elif action is Action.discard: # Nothing to do except delete the request from the database. pass elif action is Action.reject: key, data = requestdb.get_request(id) send_rejection( mlist, _('Subscription request'), data['email'], comment or _('[No reason given]'), lang=getUtility(ILanguageManager)[data['language']]) elif action is Action.accept: key, data = requestdb.get_request(id) delivery_mode = DeliveryMode[data['delivery_mode']] email = data['email'] display_name = data['display_name'] language = getUtility(ILanguageManager)[data['language']] try: add_member( mlist, RequestRecord(email, display_name, delivery_mode, language)) except AlreadySubscribedError: # The address got subscribed in some other way after the original # request was made and accepted. pass slog.info('%s: new %s, %s %s', mlist.fqdn_listname, delivery_mode, formataddr((display_name, email)), 'via admin approval') else: raise AssertionError('Unexpected action: {0}'.format(action)) # Delete the request from the database. requestdb.delete_request(id)
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 setUp(self): self._mlist = create_list('*****@*****.**') self._mlist.personalize = Personalization.individual # Make Anne a member of this mailing list. self._anne = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'xyz', DeliveryMode.regular, 'en') # Clear out any results from the previous test. del _deliveries[:] self._msg = mfs("""\ From: [email protected] To: [email protected] Subject: test """) # Set up a personalized footer for decoration. self._template_dir = tempfile.mkdtemp() path = os.path.join(self._template_dir, 'site', 'en', 'member-footer.txt') os.makedirs(os.path.dirname(path)) with open(path, 'w') as fp: print("""\ address : $user_address delivered: $user_delivered_to language : $user_language name : $user_name options : $user_optionsurl """, file=fp) config.push( 'templates', """ [paths.testing] template_dir: {0} """.format(self._template_dir)) self._mlist.footer_uri = 'mailman:///member-footer.txt' # Let assertMultiLineEqual work without bounds. self.maxDiff = None
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 = IRegistrar(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 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))
def test_add_member_password(self): # Test that the password stored with the new user is encrypted. member = add_member(self._mlist, '*****@*****.**', 'Anne Person', 'abc', DeliveryMode.regular, system_preferences.preferred_language) self.assertEqual(member.user.password, '{plaintext}abc')