def on_post(self, request, response): """POST to /addresses Add a new address to the user record. """ if self._user is None: not_found(response) return user_manager = getUtility(IUserManager) validator = Validator(email=str, display_name=str, _optional=('display_name',)) try: address = user_manager.create_address(**validator(request)) except ValueError as error: bad_request(response, str(error)) except InvalidEmailAddressError: bad_request(response, b'Invalid email address') except ExistingAddressError: # Check if the address is not linked to any user, link it to the # current user and return it. Since we're linking to an existing # address, ignore any given display_name attribute. address = user_manager.get_address(validator(request)['email']) if address.user is None: address.user = self._user location = path_to('addresses/{}'.format(address.email)) created(response, location) else: bad_request(response, 'Address belongs to other user.') else: # Link the address to the current user and return it. address.user = self._user created(response, path_to('addresses/{}'.format(address.email)))
def _resource_as_dict(self, member): """See `CollectionMixin`.""" enum, dot, role = str(member.role).partition('.') # Both the user_id and the member_id are UUIDs. We need to use the # integer equivalent in the URL. user_id = member.user.user_id.int member_id = member.member_id.int return dict( list_id=member.list_id, address=member.address.email, role=role, user=path_to('users/{0}'.format(user_id)), self_link=path_to('members/{0}'.format(member_id)), delivery_mode=member.delivery_mode, )
def process(self, args): """See `ICLISubCommand`.""" if args.output is None: output = sys.stdout else: # We don't need to close output because that will happen # automatically when the script exits. output = open(args.output, 'w') print(MAILMAN_VERSION_FULL, file=output) print('Python', sys.version, file=output) print('config file:', config.filename, file=output) print('db url:', config.db.url, file=output) print('devmode:', 'ENABLED' if as_boolean(config.devmode.enabled) else 'DISABLED', file=output) print('REST root url:', path_to('/', config.webservice.api_version), file=output) print('REST credentials: {0}:{1}'.format(config.webservice.admin_user, config.webservice.admin_pass), file=output) if args.verbose: print('File system paths:', file=output) longest = 0 paths = {} for attribute in dir(config): if attribute.endswith('_DIR') or attribute.endswith('_FILE'): paths[attribute] = getattr(config, attribute) longest = max(longest, len(attribute)) for attribute in sorted(paths): print(' {0:{2}} = {1}'.format(attribute, paths[attribute], longest))
def on_post(self, request, response): """Create a new member.""" service = getUtility(ISubscriptionService) try: validator = Validator(list_id=str, subscriber=subscriber_validator, display_name=str, delivery_mode=enum_validator(DeliveryMode), role=enum_validator(MemberRole), _optional=('delivery_mode', 'display_name', 'role')) member = service.join(**validator(request)) except AlreadySubscribedError: conflict(response, b'Member already subscribed') except NoSuchListError: bad_request(response, b'No such list') except InvalidEmailAddressError: bad_request(response, b'Invalid email address') except ValueError as error: bad_request(response, str(error)) else: # The member_id are UUIDs. We need to use the integer equivalent # in the URL. member_id = member.member_id.int location = path_to('members/{0}'.format(member_id)) created(response, location)
def create(self, request): """Create a new user.""" try: validator = Validator(email=unicode, display_name=unicode, password=unicode, _optional=('display_name', 'password')) arguments = validator(request) except ValueError as error: return http.bad_request([], str(error)) # We can't pass the 'password' argument to the user creation method, # so strip that out (if it exists), then create the user, adding the # password after the fact if successful. password = arguments.pop('password', None) try: user = getUtility(IUserManager).create_user(**arguments) except ExistingAddressError as error: return http.bad_request([], b'Address already exists {0}'.format( error.email)) if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) scheme = lookup(config.passwords.password_scheme.upper()) user.password = make_secret(password, scheme) location = path_to('users/{0}'.format(user.user_id.int)) return http.created(location, [], None)
def process(self, args): """See `ICLISubCommand`.""" if args.output is None: output = sys.stdout else: # We don't need to close output because that will happen # automatically when the script exits. output = open(args.output, 'w') print(MAILMAN_VERSION_FULL, file=output) print('Python', sys.version, file=output) print('config file:', config.filename, file=output) print('db url:', config.db.url, file=output) print('devmode:', 'ENABLED' if as_boolean(config.devmode.enabled) else 'DISABLED', file=output) print('REST root url:', path_to('/'), file=output) print('REST credentials: {0}:{1}'.format( config.webservice.admin_user, config.webservice.admin_pass), file=output) if args.verbose: print('File system paths:', file=output) longest = 0 paths = {} for attribute in dir(config): if attribute.endswith('_DIR') or attribute.endswith('_FILE'): paths[attribute] = getattr(config, attribute) longest = max(longest, len(attribute)) for attribute in sorted(paths): print(' {0:{2}} = {1}'.format( attribute, paths[attribute], longest))
def on_post(self, request, response): """Create a new member.""" service = getUtility(ISubscriptionService) try: validator = Validator( list_id=unicode, subscriber=subscriber_validator, display_name=unicode, delivery_mode=enum_validator(DeliveryMode), role=enum_validator(MemberRole), _optional=('delivery_mode', 'display_name', 'role')) member = service.join(**validator(request)) except AlreadySubscribedError: conflict(response, b'Member already subscribed') except NoSuchListError: bad_request(response, b'No such list') except InvalidEmailAddressError: bad_request(response, b'Invalid email address') except ValueError as error: bad_request(response, str(error)) else: # The member_id are UUIDs. We need to use the integer equivalent # in the URL. member_id = member.member_id.int location = path_to('members/{0}'.format(member_id)) created(response, location)
def create_user(arguments, response): """Create a new user.""" # We can't pass the 'password' argument to the user creation method, so # strip that out (if it exists), then create the user, adding the password # after the fact if successful. password = arguments.pop('password', None) is_server_owner = arguments.pop('is_server_owner', False) user_manager = getUtility(IUserManager) try: user = user_manager.create_user(**arguments) except ExistingAddressError as error: # The address already exists. If the address already has a user # linked to it, raise an error, otherwise create a new user and link # it to this address. email = arguments.pop('email') user = user_manager.get_user(email) if user is None: address = user_manager.get_address(email) user = user_manager.create_user(**arguments) user.link(address) else: bad_request(response, 'User already exists: {}'.format(error.address)) return None if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) user.password = config.password_context.encrypt(password) user.is_server_owner = is_server_owner location = path_to('users/{}'.format(user.user_id.int)) created(response, location) return user
def create(self, request): """Create a new member.""" service = getUtility(ISubscriptionService) try: validator = Validator( list_id=unicode, subscriber=subscriber_validator, display_name=unicode, delivery_mode=enum_validator(DeliveryMode), role=enum_validator(MemberRole), _optional=('delivery_mode', 'display_name', 'role')) member = service.join(**validator(request)) except AlreadySubscribedError: return http.conflict([], b'Member already subscribed') except NoSuchListError: return http.bad_request([], b'No such list') except InvalidEmailAddressError: return http.bad_request([], b'Invalid email address') except ValueError as error: return http.bad_request([], str(error)) # The member_id are UUIDs. We need to use the integer equivalent in # the URL. member_id = member.member_id.int location = path_to('members/{0}'.format(member_id)) # Include no extra headers or body. return http.created(location, [], None)
def create_user(arguments, request, response): """Create a new user.""" # We can't pass the 'password' argument to the user creation method, so # strip that out (if it exists), then create the user, adding the password # after the fact if successful. password = arguments.pop('password', None) is_server_owner = arguments.pop('is_server_owner', False) user_manager = getUtility(IUserManager) try: user = user_manager.create_user(**arguments) except ExistingAddressError as error: # The address already exists. If the address already has a user # linked to it, raise an error, otherwise create a new user and link # it to this address. email = arguments.pop('email') user = user_manager.get_user(email) if user is None: address = user_manager.get_address(email) user = user_manager.create_user(**arguments) user.link(address) else: bad_request( response, 'User already exists: {}'.format(error.address)) return None if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) user.password = config.password_context.encrypt(password) user.is_server_owner = is_server_owner location = path_to('users/{}'.format(user.user_id.int), request.context['api_version']) created(response, location) return user
def on_post(self, request, response): """Create a new user.""" try: validator = Validator(email=unicode, display_name=unicode, password=unicode, _optional=('display_name', 'password')) arguments = validator(request) except ValueError as error: bad_request(response, str(error)) return # We can't pass the 'password' argument to the user creation method, # so strip that out (if it exists), then create the user, adding the # password after the fact if successful. password = arguments.pop('password', None) try: user = getUtility(IUserManager).create_user(**arguments) except ExistingAddressError as error: bad_request( response, b'Address already exists: {0}'.format(error.address)) return if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) user.password = config.password_context.encrypt(password) location = path_to('users/{0}'.format(user.user_id.int)) created(response, location)
def on_get(self, request, response): """/<api>/system/versions""" resource = dict( mailman_version=system.mailman_version, python_version=system.python_version, self_link=path_to('system/versions'), ) okay(response, etag(resource))
def on_get(self, request, response): """/<api>/system""" resource = dict( mailman_version=system.mailman_version, python_version=system.python_version, self_link=path_to('system'), ) okay(response, etag(resource))
def _resource_as_dict(self, domain): """See `CollectionMixin`.""" return dict( base_url=domain.base_url, description=domain.description, mail_host=domain.mail_host, self_link=path_to('domains/{0}'.format(domain.mail_host)), url_host=domain.url_host, )
def _resource_as_dict(self, address): """See `CollectionMixin`.""" # The canonical url for an address is its lower-cased version, # although it can be looked up with either its original or lower-cased # email address. representation = dict( email=address.email, original_email=address.original_email, registered_on=address.registered_on, self_link=path_to("addresses/{0}".format(address.email)), ) # Add optional attributes. These can be None or the empty string. if address.display_name: representation["display_name"] = address.display_name if address.verified_on: representation["verified_on"] = address.verified_on if address.user: representation["user"] = path_to("users/{0}".format(address.user.user_id.int)) return representation
def _resource_as_dict(self, name): """See `CollectionMixin`.""" switchboard = config.switchboards[name] files = switchboard.files return dict( name=switchboard.name, directory=switchboard.queue_directory, count=len(files), files=files, self_link=path_to('queues/{}'.format(name)), )
def _resource_as_dict(self, address): """See `CollectionMixin`.""" # The canonical url for an address is its lower-cased version, # although it can be looked up with either its original or lower-cased # email address. representation = dict( email=address.email, original_email=address.original_email, registered_on=address.registered_on, self_link=path_to('addresses/{0}'.format(address.email)), ) # Add optional attributes. These can be None or the empty string. if address.display_name: representation['display_name'] = address.display_name if address.verified_on: representation['verified_on'] = address.verified_on if address.user: representation['user'] = path_to('users/{0}'.format( address.user.user_id.int)) return representation
def _resource_as_dict(self, mlist): """See `CollectionMixin`.""" return dict( display_name=mlist.display_name, fqdn_listname=mlist.fqdn_listname, list_name=mlist.list_name, mail_host=mlist.mail_host, member_count=mlist.members.member_count, volume=mlist.volume, self_link=path_to('lists/{0}'.format(mlist.fqdn_listname)), )
def _resource_as_dict(self, mlist): """See `CollectionMixin`.""" return dict( display_name=mlist.display_name, fqdn_listname=mlist.fqdn_listname, list_id=mlist.list_id, list_name=mlist.list_name, mail_host=mlist.mail_host, member_count=mlist.members.member_count, volume=mlist.volume, self_link=path_to('lists/{0}'.format(mlist.list_id)), )
def _resource_as_dict(self, member): """See `CollectionMixin`.""" enum, dot, role = str(member.role).partition('.') # The member will always have a member id and an address id. It will # only have a user id if the address is linked to a user. # E.g. nonmembers we've only seen via postings to lists they are not # subscribed to will not have a user id. The user_id and the # member_id are UUIDs. We need to use the integer equivalent in the # URL. response = dict( list_id=member.list_id, email=member.address.email, role=role, address=path_to('addresses/{}'.format(member.address.email)), self_link=path_to('members/{}'.format(member.member_id.int)), delivery_mode=member.delivery_mode, ) # Add the user link if there is one. user = member.user if user is not None: response['user'] = path_to('users/{}'.format(user.user_id.int)) return response
def system(self, request, segments): """/<api>/system""" if len(segments) == 0: resource = dict( mailman_version=system.mailman_version, python_version=system.python_version, self_link=path_to('system'), ) elif len(segments) > 1: return http.bad_request() elif segments[0] == 'preferences': return ReadOnlyPreferences(system_preferences, 'system'), [] else: return http.bad_request() return http.ok([], etag(resource))
def _resource_as_dict(self, member): """See `CollectionMixin`.""" enum, dot, role = str(member.role).partition('.') # The member will always have a member id and an address id. It will # only have a user id if the address is linked to a user. # E.g. nonmembers we've only seen via postings to lists they are not # subscribed to will not have a user id. The user_id and the # member_id are UUIDs. We need to use the integer equivalent in the # URL. member_id = member.member_id.int response = dict( list_id=member.list_id, email=member.address.email, role=role, address=path_to('addresses/{}'.format(member.address.email)), self_link=path_to('members/{}'.format(member_id)), delivery_mode=member.delivery_mode, member_id=member_id, ) # Add the user link if there is one. user = member.user if user is not None: response['user'] = path_to('users/{}'.format(user.user_id.int)) return response
def on_post(self, request, response): """Create a new mailing list.""" try: validator = Validator(fqdn_listname=str, style_name=str, _optional=('style_name',)) mlist = create_list(**validator(request)) except ListAlreadyExistsError: bad_request(response, b'Mailing list exists') except BadDomainSpecificationError as error: reason = 'Domain does not exist: {}'.format(error.domain) bad_request(response, reason.encode('utf-8')) except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('lists/{0}'.format(mlist.list_id)))
def create(self, request): """Create a new mailing list.""" try: validator = Validator(fqdn_listname=unicode) mlist = create_list(**validator(request)) except ListAlreadyExistsError: return http.bad_request([], b'Mailing list exists') except BadDomainSpecificationError as error: return http.bad_request([], b'Domain does not exist {0}'.format( error.domain)) except ValueError as error: return http.bad_request([], str(error)) # wsgiref wants headers to be bytes, not unicodes. location = path_to('lists/{0}'.format(mlist.fqdn_listname)) # Include no extra headers or body. return http.created(location, [], None)
def on_post(self, request, response): """Create a new mailing list.""" try: validator = Validator(fqdn_listname=str, style_name=str, _optional=('style_name', )) mlist = create_list(**validator(request)) except ListAlreadyExistsError: bad_request(response, b'Mailing list exists') except BadDomainSpecificationError as error: reason = 'Domain does not exist: {}'.format(error.domain) bad_request(response, reason.encode('utf-8')) except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('lists/{0}'.format(mlist.list_id)))
def on_post(self, request, response): """Create a new domain.""" domain_manager = getUtility(IDomainManager) try: validator = Validator(mail_host=str, description=str, base_url=str, contact_address=str, _optional=('description', 'base_url', 'contact_address')) domain = domain_manager.add(**validator(request)) except BadDomainSpecificationError: bad_request(response, b'Domain exists') except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('domains/{0}'.format(domain.mail_host)))
def on_get(self, request, response): resource = dict() for attr in PREFERENCES: # Handle this one specially. if attr == 'preferred_language': continue value = getattr(self._parent, attr, None) if value is not None: resource[attr] = value # Add the preferred language, if it's not missing. preferred_language = self._parent.preferred_language if preferred_language is not None: resource['preferred_language'] = preferred_language.code # Add the self link. resource['self_link'] = path_to( '{0}/preferences'.format(self._base_url)) okay(response, etag(resource))
def on_post(self, request, response): """Create a new domain.""" domain_manager = getUtility(IDomainManager) try: validator = Validator(mail_host=unicode, description=unicode, base_url=unicode, contact_address=unicode, _optional=('description', 'base_url', 'contact_address')) domain = domain_manager.add(**validator(request)) except BadDomainSpecificationError: bad_request(response, b'Domain exists') except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('domains/{0}'.format(domain.mail_host)))
def on_get(self, request, response): resource = dict() for attr in PREFERENCES: # Handle this one specially. if attr == 'preferred_language': continue value = getattr(self._parent, attr, None) if value is not None: resource[attr] = value # Add the preferred language, if it's not missing. preferred_language = self._parent.preferred_language if preferred_language is not None: resource['preferred_language'] = preferred_language.code # Add the self link. resource['self_link'] = path_to( '{0}/preferences'.format(self._base_url), self.api_version) okay(response, etag(resource))
def create(self, request): """Create a new domain.""" domain_manager = getUtility(IDomainManager) try: validator = Validator(mail_host=unicode, description=unicode, base_url=unicode, contact_address=unicode, _optional=('description', 'base_url', 'contact_address')) domain = domain_manager.add(**validator(request)) except BadDomainSpecificationError: return http.bad_request([], b'Domain exists') except ValueError as error: return http.bad_request([], str(error)) location = path_to('domains/{0}'.format(domain.mail_host)) # Include no extra headers or body. return http.created(location, [], None)
def _resource_as_dict(self, user): """See `CollectionMixin`.""" # The canonical URL for a user is their unique user id, although we # can always look up a user based on any registered and validated # email address associated with their account. The user id is a UUID, # but we serialize its integer equivalent. user_id = user.user_id.int resource = dict( user_id=user_id, created_on=user.created_on, self_link=path_to('users/{}'.format(user_id)), ) # Add the password attribute, only if the user has a password. Same # with the real name. These could be None or the empty string. if user.password: resource['password'] = user.password if user.display_name: resource['display_name'] = user.display_name return resource
def create_user(arguments, response): """Create a new user.""" # We can't pass the 'password' argument to the user creation method, so # strip that out (if it exists), then create the user, adding the password # after the fact if successful. password = arguments.pop('password', None) try: user = getUtility(IUserManager).create_user(**arguments) except ExistingAddressError as error: bad_request( response, 'Address already exists: {}'.format(error.address)) return None if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) user.password = config.password_context.encrypt(password) location = path_to('users/{}'.format(user.user_id.int)) created(response, location) return user
def _resource_as_dict(self, user): """See `CollectionMixin`.""" # The canonical URL for a user is their unique user id, although we # can always look up a user based on any registered and validated # email address associated with their account. The user id is a UUID, # but we serialize its integer equivalent. user_id = user.user_id.int resource = dict( user_id=user_id, created_on=user.created_on, self_link=path_to('users/{0}'.format(user_id)), ) # Add the password attribute, only if the user has a password. Same # with the real name. These could be None or the empty string. if user.password: resource['password'] = user.password if user.display_name: resource['display_name'] = user.display_name return resource
def create_user(arguments, response): """Create a new user.""" # We can't pass the 'password' argument to the user creation method, so # strip that out (if it exists), then create the user, adding the password # after the fact if successful. password = arguments.pop('password', None) is_server_owner = arguments.pop('is_server_owner', False) try: user = getUtility(IUserManager).create_user(**arguments) except ExistingAddressError as error: bad_request( response, 'Address already exists: {}'.format(error.address)) return None if password is None: # This will have to be reset since it cannot be retrieved. password = generate(int(config.passwords.password_length)) user.password = config.password_context.encrypt(password) user.is_server_owner = is_server_owner location = path_to('users/{}'.format(user.user_id.int)) created(response, location) return user
def on_post(self, request, response): """POST to /addresses Add a new address to the user record. """ if self._user is None: not_found(response) return user_manager = getUtility(IUserManager) validator = Validator(email=str, display_name=str, _optional=("display_name",)) try: address = user_manager.create_address(**validator(request)) except ValueError as error: bad_request(response, str(error)) except InvalidEmailAddressError: bad_request(response, b"Invalid email address") except ExistingAddressError: bad_request(response, b"Address already exists") else: # Link the address to the current user and return it. address.user = self._user created(response, path_to("addresses/{0}".format(address.email)))
def on_post(self, request, response): """Create a new domain.""" domain_manager = getUtility(IDomainManager) try: validator = Validator(mail_host=str, description=str, base_url=str, owner=list_of_strings_validator, _optional=('description', 'base_url', 'owner')) values = validator(request) # For consistency, owners are passed in as multiple `owner` keys, # but .add() requires an `owners` keyword. Match impedence. owners = values.pop('owner', None) if owners is not None: values['owners'] = owners domain = domain_manager.add(**values) except BadDomainSpecificationError as error: bad_request(response, str(error)) except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('domains/{0}'.format(domain.mail_host)))
def on_post(self, request, response): """Inject a message into the queue.""" try: validator = Validator(list_id=str, text=str) values = validator(request) except ValueError as error: bad_request(response, str(error)) return list_id = values['list_id'] mlist = getUtility(IListManager).get_by_list_id(list_id) if mlist is None: bad_request(response, 'No such list: {}'.format(list_id)) return try: filebase = inject_text( mlist, values['text'], switchboard=self._name) except Exception as error: bad_request(response, str(error)) return else: location = path_to('queues/{}/{}'.format(self._name, filebase)) created(response, location)
def on_post(self, request, response): """Create a new domain.""" domain_manager = getUtility(IDomainManager) try: validator = Validator(mail_host=str, description=str, base_url=str, owner=list_of_strings_validator, _optional=( 'description', 'base_url', 'owner')) values = validator(request) # For consistency, owners are passed in as multiple `owner` keys, # but .add() requires an `owners` keyword. Match impedence. owners = values.pop('owner', None) if owners is not None: values['owners'] = owners domain = domain_manager.add(**values) except BadDomainSpecificationError as error: bad_request(response, str(error)) except ValueError as error: bad_request(response, str(error)) else: created(response, path_to('domains/{0}'.format(domain.mail_host)))
def on_post(self, request, response): """Inject a message into the queue.""" try: validator = Validator(list_id=str, text=str) values = validator(request) except ValueError as error: bad_request(response, str(error)) return list_id = values['list_id'] mlist = getUtility(IListManager).get_by_list_id(list_id) if mlist is None: bad_request(response, 'No such list: {}'.format(list_id)) return try: filebase = inject_text(mlist, values['text'], switchboard=self._name) except Exception as error: bad_request(response, str(error)) return else: location = path_to('queues/{}/{}'.format(self._name, filebase)) created(response, location)
def on_post(self, request, response): """POST to /addresses Add a new address to the user record. """ if self._user is None: not_found(response) return user_manager = getUtility(IUserManager) validator = Validator(email=str, display_name=str, _optional=('display_name', )) try: address = user_manager.create_address(**validator(request)) except ValueError as error: bad_request(response, str(error)) except InvalidEmailAddressError: bad_request(response, b'Invalid email address') except ExistingAddressError: bad_request(response, b'Address already exists') else: # Link the address to the current user and return it. address.user = self._user created(response, path_to('addresses/{0}'.format(address.email)))
def create(self, request): """POST to /addresses Add a new address to the user record. """ if self._user is None: return http.not_found() user_manager = getUtility(IUserManager) validator = Validator(email=unicode, display_name=unicode, _optional=('display_name',)) try: address = user_manager.create_address(**validator(request)) except ValueError as error: return http.bad_request([], str(error)) except InvalidEmailAddressError: return http.bad_request([], b'Invalid email address') except ExistingAddressError: return http.bad_request([], b'Address already exists') else: # Link the address to the current user and return it. address.user = self._user location = path_to('addresses/{0}'.format(address.email)) return http.created(location, [], None)
def on_get(self, request, response): """<api>/queues""" resource = self._make_collection(request) resource['self_link'] = path_to('queues') okay(response, etag(resource))
def on_post(self, request, response): """Create a new member.""" try: validator = Validator(list_id=str, subscriber=subscriber_validator, 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 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 = member.member_id.int location = path_to('members/{0}'.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 InvalidEmailAddressError: bad_request(response, b'Invalid email address') return except MembershipIsBannedError: bad_request(response, b'Membership is banned') 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 = member.member_id.int location = path_to('members/{0}'.format(member_id)) created(response, location) return
def on_post(self, request, response): """Create a new member.""" try: validator = Validator( list_id=str, subscriber=subscriber_validator, 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 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 = member.member_id.int location = path_to('members/{0}'.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 InvalidEmailAddressError: bad_request(response, b'Invalid email address') return except MembershipIsBannedError: bad_request(response, b'Membership is banned') 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 = member.member_id.int location = path_to('members/{0}'.format(member_id)) created(response, location) return