Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 def test_http_conflict_with_bytes_body(self):
     response = FakeResponse()
     helpers.conflict(response, b'Conflicting request')
     self.assertEqual(response.content_type,
                      'application/json; charset=UTF-8')
     self.assertEqual(json.loads(response.body), {
         'title': '409 Conflict',
         'description': 'Conflicting request',
     })
 def on_post(self, request, response):
     try:
         validator = Validator(action=enum_validator(Action),
                               reason=str,
                               _optional=('reason',))
         arguments = validator(request)
     except ValueError as error:
         bad_request(response, str(error))
         return
     action = arguments['action']
     if action in (Action.defer, Action.hold):
         # At least see if the token is in the database.
         pendable = self._pendings.confirm(self._token, expunge=False)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
     elif action is Action.accept:
         try:
             self._registrar.confirm(self._token)
         except LookupError:
             not_found(response)
         except AlreadySubscribedError:
             conflict(response, 'Already subscribed')
         else:
             no_content(response)
     elif action is Action.discard:
         # At least see if the token is in the database.
         pendable = self._pendings.confirm(self._token, expunge=True)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
     else:
         assert action is Action.reject, action
         # Like discard but sends a rejection notice to the user.
         pendable = self._pendings.confirm(self._token, expunge=True)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
             reason = arguments.get('reason', _('[No reason given]'))
             send_rejection(
                 self._mlist, _('Subscription request'),
                 pendable['email'], reason)
Ejemplo n.º 5
0
 def on_post(self, request, response):
     try:
         validator = Validator(action=enum_validator(Action))
         arguments = validator(request)
     except ValueError as error:
         bad_request(response, str(error))
         return
     action = arguments['action']
     if action in (Action.defer, Action.hold):
         # At least see if the token is in the database.
         pendable = self._pendings.confirm(self._token, expunge=False)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
     elif action is Action.accept:
         try:
             self._registrar.confirm(self._token)
         except LookupError:
             not_found(response)
         except AlreadySubscribedError:
             conflict(response, 'Already subscribed')
         else:
             no_content(response)
     elif action is Action.discard:
         # At least see if the token is in the database.
         pendable = self._pendings.confirm(self._token, expunge=True)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
     else:
         assert action is Action.reject, action
         # Like discard but sends a rejection notice to the user.
         pendable = self._pendings.confirm(self._token, expunge=True)
         if pendable is None:
             not_found(response)
         else:
             no_content(response)
             send_rejection(
                 self._mlist, _('Subscription request'),
                 pendable['email'],
                 _('[No reason given]'))
Ejemplo n.º 6
0
 def on_post(self, request, response):
     """Link a user to the address, and create it if needed."""
     if self._user:
         conflict(response)
         return
     # When creating a linked user by POSTing, the user either must already
     # exist, or it can be automatically created, if the auto_create flag
     # is given and true (if missing, it defaults to true).  However, in
     # this case we do not accept 'email' as a POST field.
     fields = CREATION_FIELDS.copy()
     del fields['email']
     fields['user_id'] = self.api.to_uuid
     fields['auto_create'] = as_boolean
     fields['_optional'] = fields['_optional'] + ('user_id', 'auto_create',
                                                  'is_server_owner')
     try:
         validator = Validator(**fields)
         arguments = validator(request)
     except ValueError as error:
         bad_request(response, str(error))
         return
     user_manager = getUtility(IUserManager)
     if 'user_id' in arguments:
         user_id = arguments['user_id']
         user = user_manager.get_user_by_id(user_id)
         if user is None:
             bad_request(
                 response, 'No user with ID {}'.format(
                     self.api.from_uuid(user_id)).encode())
             return
         okay(response)
     else:
         auto_create = arguments.pop('auto_create', True)
         if auto_create:
             # This sets the 201 or 400 status.
             user = create_user(self.api, arguments, response)
             if user is None:
                 return
         else:
             forbidden(response)
             return
     user.link(self._address)
Ejemplo n.º 7
0
 def on_post(self, request, response):
     """Link a user to the address, and create it if needed."""
     if self._user:
         conflict(response)
         return
     # When creating a linked user by POSTing, the user either must already
     # exist, or it can be automatically created, if the auto_create flag
     # is given and true (if missing, it defaults to true).  However, in
     # this case we do not accept 'email' as a POST field.
     fields = CREATION_FIELDS.copy()
     del fields['email']
     fields['user_id'] = int
     fields['auto_create'] = as_boolean
     fields['_optional'] = fields['_optional'] + (
         'user_id', 'auto_create', 'is_server_owner')
     try:
         validator = Validator(**fields)
         arguments = validator(request)
     except ValueError as error:
         bad_request(response, str(error))
         return
     user_manager = getUtility(IUserManager)
     if 'user_id' in arguments:
         raw_uid = arguments['user_id']
         user_id = UUID(int=raw_uid)
         user = user_manager.get_user_by_id(user_id)
         if user is None:
             not_found(response, b'No user with ID {}'.format(raw_uid))
             return
         okay(response)
     else:
         auto_create = arguments.pop('auto_create', True)
         if auto_create:
             # This sets the 201 or 400 status.
             user = create_user(arguments, request, response)
             if user is None:
                 return
         else:
             forbidden(response)
             return
     user.link(self._address)
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
 def test_conflict_body_is_none(self):
     response = FakeResponse()
     helpers.conflict(response, body=None)
     self.assertEqual(response.body, "not set")
Ejemplo n.º 11
0
 def test_conflict_body_is_none(self):
     response = FakeResponse()
     helpers.conflict(response, body=None)
     self.assertEqual(response.body, 'not set')