Esempio n. 1
0
 def test_subscribed_as_user_and_address(self):
     # Anne subscribes to a mailing list twice, once as a user and once
     # with an explicit address.  She has two memberships.
     self._ant.subscribe(self._anne)
     self._ant.subscribe(self._anne.preferred_address)
     self.assertEqual(self._anne.memberships.member_count, 2)
     self.assertEqual(self._ant.members.member_count, 2)
     self.assertEqual(
         [member.address.email for member in self._ant.members.members],
         ['*****@*****.**', '*****@*****.**'])
     # get_member() is defined to return the explicit address.
     member = self._ant.members.get_member('*****@*****.**')
     subscriber = member.subscriber
     self.assertTrue(IAddress.providedBy(subscriber))
     self.assertFalse(IUser.providedBy(subscriber))
     # get_memberships() returns them all.
     memberships = self._ant.members.get_memberships('*****@*****.**')
     self.assertEqual(len(memberships), 2)
     as_address = (memberships[0]
                   if IAddress.providedBy(memberships[0].subscriber)
                   else memberships[1])
     as_user = (memberships[1]
                if IUser.providedBy(memberships[1].subscriber)
                else memberships[0])
     self.assertEqual(as_address.subscriber, self._anne.preferred_address)
     self.assertEqual(as_user.subscriber, self._anne)
     # All the email addresses match.
     self.assertEqual(
         [record.address.email for record in memberships],
         ['*****@*****.**', '*****@*****.**'])
Esempio n. 2
0
 def test_subscribed_as_user_and_address(self):
     # Anne subscribes to a mailing list twice, once as a user and once
     # with an explicit address.  She has two memberships.
     self._ant.subscribe(self._anne)
     self._ant.subscribe(self._anne.preferred_address)
     self.assertEqual(self._anne.memberships.member_count, 2)
     self.assertEqual(self._ant.members.member_count, 2)
     self.assertEqual(
         [member.address.email for member in self._ant.members.members],
         ['*****@*****.**', '*****@*****.**'])
     # get_member() is defined to return the explicit address.
     member = self._ant.members.get_member('*****@*****.**')
     subscriber = member.subscriber
     self.assertTrue(IAddress.providedBy(subscriber))
     self.assertFalse(IUser.providedBy(subscriber))
     # get_memberships() returns them all.
     memberships = self._ant.members.get_memberships('*****@*****.**')
     self.assertEqual(len(memberships), 2)
     as_address = (memberships[0] if IAddress.providedBy(
         memberships[0].subscriber) else memberships[1])
     as_user = (memberships[1] if IUser.providedBy(
         memberships[1].subscriber) else memberships[0])
     self.assertEqual(as_address.subscriber, self._anne.preferred_address)
     self.assertEqual(as_user.subscriber, self._anne)
     # All the email addresses match.
     self.assertEqual([record.address.email for record in memberships],
                      ['*****@*****.**', '*****@*****.**'])
Esempio n. 3
0
 def subscribe(self, store, subscriber, role=MemberRole.member):
     """See `IMailingList`."""
     if IAddress.providedBy(subscriber):
         member = store.query(Member).filter(
             Member.role == role, Member.list_id == self._list_id,
             Member._address == subscriber).first()
         if member:
             raise AlreadySubscribedError(self.fqdn_listname,
                                          subscriber.email, role)
     elif IUser.providedBy(subscriber):
         if subscriber.preferred_address is None:
             raise MissingPreferredAddressError(subscriber)
         member = store.query(Member).filter(
             Member.role == role, Member.list_id == self._list_id,
             Member._user == subscriber).first()
         if member:
             raise AlreadySubscribedError(
                 self.fqdn_listname, subscriber.preferred_address.email,
                 role)
     else:
         raise ValueError('subscriber must be an address or user')
     member = Member(role=role,
                     list_id=self._list_id,
                     subscriber=subscriber)
     member.preferences = Preferences()
     store.add(member)
     notify(SubscriptionEvent(self, member))
     return member
Esempio n. 4
0
 def __init__(self,
              mlist,
              subscriber=None,
              *,
              pre_verified=False,
              pre_confirmed=False,
              pre_approved=False):
     super().__init__()
     self.mlist = mlist
     self.address = None
     self.user = None
     self.which = None
     self.member = None
     self._set_token(TokenOwner.no_one)
     # The subscriber must be either an IUser or IAddress.
     if IAddress.providedBy(subscriber):
         self.address = subscriber
         self.user = self.address.user
         self.which = WhichSubscriber.address
     elif IUser.providedBy(subscriber):
         self.address = subscriber.preferred_address
         self.user = subscriber
         self.which = WhichSubscriber.user
     self.subscriber = subscriber
     self.pre_verified = pre_verified
     self.pre_confirmed = pre_confirmed
     self.pre_approved = pre_approved
    def _get_subscriber(self, store, subscriber, role):
        """Get some information about a user/address.

        Returns a 2-tuple of (member, email) for the given subscriber.  If the
        subscriber is is not an ``IAddress`` or ``IUser``, then a 2-tuple of
        (None, None) is returned.  If the subscriber is not already
        subscribed, then (None, email) is returned.  If the subscriber is an
        ``IUser`` and does not have a preferred address, (member, None) is
        returned.
        """
        member = None
        email = None
        if IAddress.providedBy(subscriber):
            member = store.query(Member).filter(
                Member.role == role,
                Member.list_id == self._list_id,
                Member._address == subscriber).first()
            email = subscriber.email
        elif IUser.providedBy(subscriber):
            if subscriber.preferred_address is None:
                raise MissingPreferredAddressError(subscriber)
            email = subscriber.preferred_address.email
            member = store.query(Member).filter(
                Member.role == role,
                Member.list_id == self._list_id,
                Member._user == subscriber).first()
        return member, email
Esempio n. 6
0
 def subscribe(self, subscriber, role=MemberRole.member):
     """See `IMailingList`."""
     store = Store.of(self)
     if IAddress.providedBy(subscriber):
         member = store.find(
             Member,
             Member.role == role,
             Member.mailing_list == self.fqdn_listname,
             Member._address == subscriber).one()
         if member:
             raise AlreadySubscribedError(
                 self.fqdn_listname, subscriber.email, role)
     elif IUser.providedBy(subscriber):
         if subscriber.preferred_address is None:
             raise MissingPreferredAddressError(subscriber)
         member = store.find(
             Member,
             Member.role == role,
             Member.mailing_list == self.fqdn_listname,
             Member._user == subscriber).one()
         if member:
             raise AlreadySubscribedError(
                 self.fqdn_listname, subscriber, role)
     else:
         raise ValueError('subscriber must be an address or user')
     member = Member(role=role,
                     mailing_list=self.fqdn_listname,
                     subscriber=subscriber)
     member.preferences = Preferences()
     store.add(member)
     return member
Esempio n. 7
0
 def subscribe(self, store, subscriber, role=MemberRole.member):
     """See `IMailingList`."""
     if IAddress.providedBy(subscriber):
         member = store.query(Member).filter(
             Member.role == role,
             Member.list_id == self._list_id,
             Member._address == subscriber).first()
         if member:
             raise AlreadySubscribedError(
                 self.fqdn_listname, subscriber.email, role)
     elif IUser.providedBy(subscriber):
         if subscriber.preferred_address is None:
             raise MissingPreferredAddressError(subscriber)
         member = store.query(Member).filter(
             Member.role == role,
             Member.list_id == self._list_id,
             Member._user == subscriber).first()
         if member:
             raise AlreadySubscribedError(
                 self.fqdn_listname,
                 subscriber.preferred_address.email,
                 role)
     else:
         raise ValueError('subscriber must be an address or user')
     member = Member(role=role,
                     list_id=self._list_id,
                     subscriber=subscriber)
     member.preferences = Preferences()
     store.add(member)
     notify(SubscriptionEvent(self, member))
     return member
def handle_SubscriptionEvent(event):
    if not isinstance(event, SubscriptionEvent):
        return
    member = event.member
    # Only send notifications if a member (as opposed to a moderator,
    # non-member, or owner) is being subscribed.
    if member.role is not MemberRole.member:
        return
    mlist = member.mailing_list
    # Maybe send the list administrators a notification.
    if mlist.admin_notify_mchanges:
        subscriber = member.subscriber
        if IAddress.providedBy(subscriber):
            address = subscriber.email
            display_name = subscriber.display_name
        else:
            assert IUser.providedBy(subscriber)
            address = subscriber.preferred_address.email
            display_name = subscriber.display_name
        send_admin_subscription_notice(mlist, address, display_name)
    # Maybe send a welcome message to the new member. The event's flag
    # overrides the mailinglist's configuration, iff it is non-None.
    if ((event.send_welcome_message is None and mlist.send_welcome_message)
            or event.send_welcome_message):
        send_welcome_message(mlist, member, member.preferred_language)
Esempio n. 9
0
 def add_owner(self, owner):
     """See `IDomain`."""
     user_manager = getUtility(IUserManager)
     if IUser.providedBy(owner):
         user = owner
     else:
         user = user_manager.get_user(owner)
     # BAW 2015-04-06: Make sure this path is tested.
     if user is None:
         user = user_manager.create_user(owner)
     self.owners.append(user)
Esempio n. 10
0
 def add_owner(self, owner):
     """See `IDomain`."""
     user_manager = getUtility(IUserManager)
     if IUser.providedBy(owner):
         user = owner
     else:
         user = user_manager.get_user(owner)
     # BAW 2015-04-06: Make sure this path is tested.
     if user is None:
         user = user_manager.create_user(owner)
     self.owners.append(user)
Esempio n. 11
0
 def __init__(self,
              mlist,
              subscriber=None,
              *,
              pre_approved=False,
              pre_confirmed=False):
     super().__init__(mlist, subscriber)
     if IAddress.providedBy(subscriber) or IUser.providedBy(subscriber):
         self.member = self.mlist.regular_members.get_member(
             self.address.email)
     self.pre_confirmed = pre_confirmed
     self.pre_approved = pre_approved
Esempio n. 12
0
 def __init__(self, role, list_id, subscriber):
     self._member_id = uid_factory.new()
     self.role = role
     self.list_id = list_id
     if IAddress.providedBy(subscriber):
         self._address = subscriber
         # Look this up dynamically.
         self._user = None
     elif IUser.providedBy(subscriber):
         self._user = subscriber
         # Look this up dynamically.
         self._address = None
     else:
         raise ValueError('subscriber must be a user or address')
     if role in (MemberRole.owner, MemberRole.moderator):
         self.moderation_action = Action.accept
     else:
         assert role in (MemberRole.member, MemberRole.nonmember), (
             'Invalid MemberRole: {}'.format(role))
         self.moderation_action = None
Esempio n. 13
0
 def __init__(self, role, list_id, subscriber):
     self._member_id = uid_factory.new()
     self.role = role
     self.list_id = list_id
     if IAddress.providedBy(subscriber):
         self._address = subscriber
         # Look this up dynamically.
         self._user = None
     elif IUser.providedBy(subscriber):
         self._user = subscriber
         # Look this up dynamically.
         self._address = None
     else:
         raise ValueError('subscriber must be a user or address')
     if role in (MemberRole.owner, MemberRole.moderator):
         self.moderation_action = Action.accept
     else:
         assert role in (MemberRole.member, MemberRole.nonmember), (
             'Invalid MemberRole: {}'.format(role))
         self.moderation_action = None
Esempio n. 14
0
 def __init__(self, role, list_id, subscriber):
     self._member_id = uid_factory.new_uid()
     self.role = role
     self.list_id = list_id
     if IAddress.providedBy(subscriber):
         self._address = subscriber
         # Look this up dynamically.
         self._user = None
     elif IUser.providedBy(subscriber):
         self._user = subscriber
         # Look this up dynamically.
         self._address = None
     else:
         raise ValueError("subscriber must be a user or address")
     if role in (MemberRole.owner, MemberRole.moderator):
         self.moderation_action = Action.accept
     elif role is MemberRole.member:
         self.moderation_action = getUtility(IListManager).get_by_list_id(list_id).default_member_action
     else:
         assert role is MemberRole.nonmember, "Invalid MemberRole: {0}".format(role)
         self.moderation_action = getUtility(IListManager).get_by_list_id(list_id).default_nonmember_action
Esempio n. 15
0
 def __init__(self, mlist, subscriber=None, *, pre_verified=False, pre_confirmed=False, pre_approved=False):
     super().__init__()
     self.mlist = mlist
     self.address = None
     self.user = None
     self.which = None
     self.member = None
     self._set_token(TokenOwner.no_one)
     # The subscriber must be either an IUser or IAddress.
     if IAddress.providedBy(subscriber):
         self.address = subscriber
         self.user = self.address.user
         self.which = WhichSubscriber.address
     elif IUser.providedBy(subscriber):
         self.address = subscriber.preferred_address
         self.user = subscriber
         self.which = WhichSubscriber.user
     self.subscriber = subscriber
     self.pre_verified = pre_verified
     self.pre_confirmed = pre_confirmed
     self.pre_approved = pre_approved
Esempio n. 16
0
def handle_SubscriptionEvent(event):
    if not isinstance(event, SubscriptionEvent):
        return
    member = event.member
    # Only send notifications if a member (as opposed to a moderator,
    # non-member, or owner) is being subscribed.
    if member.role is not MemberRole.member:
        return
    mlist = member.mailing_list
    # Maybe send the list administrators a notification.
    if mlist.admin_notify_mchanges:
        subscriber = member.subscriber
        if IAddress.providedBy(subscriber):
            address = subscriber.email
            display_name = subscriber.display_name
        else:
            assert IUser.providedBy(subscriber)
            address = subscriber.preferred_address.email
            display_name = subscriber.display_name
        send_admin_subscription_notice(mlist, address, display_name)
    # Maybe send a welcome message to the new member.
    if mlist.send_welcome_message:
        send_welcome_message(mlist, member, member.preferred_language)
Esempio n. 17
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)
Esempio n. 18
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)