diff options
| author | Barry Warsaw | 2008-09-24 22:22:29 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2008-09-24 22:22:29 -0400 |
| commit | c129b48a91d11fd3fb69666b8109c3a9372b2f8f (patch) | |
| tree | e63e9d6ffcf552472de3076c0739d4871400e586 | |
| parent | 546825b4ec7a1018bc2182646e8c0433271d1990 (diff) | |
| download | mailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.tar.gz mailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.tar.zst mailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.zip | |
| -rw-r--r-- | mailman/app/registrar.py | 45 | ||||
| -rw-r--r-- | mailman/commands/docs/join.txt | 41 | ||||
| -rw-r--r-- | mailman/commands/join.py | 66 | ||||
| -rw-r--r-- | mailman/docs/registration.txt | 59 | ||||
| -rw-r--r-- | mailman/interfaces/registrar.py | 2 |
5 files changed, 95 insertions, 118 deletions
diff --git a/mailman/app/registrar.py b/mailman/app/registrar.py index a0c3e56a7..692e25748 100644 --- a/mailman/app/registrar.py +++ b/mailman/app/registrar.py @@ -34,6 +34,7 @@ from mailman.Utils import ValidateEmail from mailman.configuration import config from mailman.i18n import _ from mailman.interfaces import IDomain, IPendable, IRegistrar +from mailman.interfaces.member import MemberRole @@ -49,29 +50,18 @@ class Registrar: def __init__(self, context): self._context = context - def register(self, address, real_name=None): + def register(self, address, real_name=None, mlist=None): """See `IUserRegistrar`.""" # First, do validation on the email address. If the address is # invalid, it will raise an exception, otherwise it just returns. ValidateEmail(address) - # Check to see if there is already a verified IAddress in the database - # matching this address. If so, there's nothing to do. - usermgr = config.db.user_manager - addr = usermgr.get_address(address) - if addr and addr.verified_on: - # Before returning, see if this address is linked to a user. If - # not, create one and link it now since no future verification - # will be done. - user = usermgr.get_user(address) - if user is None: - user = usermgr.create_user() - user.real_name = (real_name if real_name else addr.real_name) - user.link(addr) - return None - # Calculate the token for this confirmation record. - pendable = PendableRegistration(type=PendableRegistration.PEND_KEY, - address=address, - real_name=real_name) + # Create a pendable for the registration. + pendable = PendableRegistration( + type=PendableRegistration.PEND_KEY, + address=address, + real_name=real_name) + if mlist is not None: + pendable['list_name'] = mlist.fqdn_listname token = config.db.pendings.add(pendable) # Set up some local variables for translation interpolation. domain = IDomain(self._context) @@ -100,8 +90,8 @@ class Registrar: missing = object() address = pendable.get('address', missing) real_name = pendable.get('real_name', missing) - if (pendable.get('type') <> PendableRegistration.PEND_KEY or - address is missing or real_name is missing): + list_name = pendable.get('list_name', missing) + if pendable.get('type') != PendableRegistration.PEND_KEY: # It seems like it would be very difficult to accurately guess # tokens, or brute force an attack on the SHA1 hash, so we'll just # throw the pendable away in that case. It's possible we'll need @@ -112,8 +102,10 @@ class Registrar: # and an IUser linked to this IAddress. See if any of these objects # currently exist in our database. usermgr = config.db.user_manager - addr = usermgr.get_address(address) - user = usermgr.get_user(address) + addr = (usermgr.get_address(address) + if address is not missing else None) + user = (usermgr.get_user(address) + if address is not missing else None) # If there is neither an address nor a user matching the confirmed # record, then create the user, which will in turn create the address # and link the two together @@ -138,6 +130,13 @@ class Registrar: # do is verify the address. pass addr.verified_on = datetime.datetime.now() + # If this registration is tied to a mailing list, subscribe the person + # to the list right now. + list_name = pendable.get('list_name') + if list_name is not None: + mlist = config.db.list_manager.get(list_name) + if mlist: + addr.subscribe(mlist, MemberRole.member) return True def discard(self, token): diff --git a/mailman/commands/docs/join.txt b/mailman/commands/docs/join.txt index 4cc805e99..492297787 100644 --- a/mailman/commands/docs/join.txt +++ b/mailman/commands/docs/join.txt @@ -29,7 +29,7 @@ No address to join >>> from mailman.Message import Message >>> from mailman.app.lifecycle import create_list >>> from mailman.queue.command import Results - >>> mlist = create_list(u'test@example.com') + >>> mlist = create_list(u'alpha@example.com') When no address argument is given, the message's From address will be used. If that's missing though, then an error is returned. @@ -131,3 +131,42 @@ list. Anne Person >>> list(user.addresses) [<Address: Anne Person <anne@example.com> [verified] at ...>] + +Anne is also now a member of the mailing list. + + >>> mlist.members.get_member(u'anne@example.com') + <Member: Anne Person <anne@example.com> + on alpha@example.com as MemberRole.member> + + +Joining a second list +--------------------- + + >>> mlist_2 = create_list(u'baker@example.com') + >>> msg = message_from_string("""\ + ... From: Anne Person <anne@example.com> + ... + ... """) + >>> print command.process(mlist_2, msg, {}, (), Results()) + ContinueProcessing.yes + +Anne of course, is still registered. + + >>> print config.db.user_manager.get_user(u'anne@example.com') + <User "Anne Person" at ...> + +But she is not a member of the mailing list. + + >>> print mlist_2.members.get_member(u'anne@example.com') + None + +One Anne confirms this subscription, she becomes a member of the mailing list. + + >>> qmsg, qdata = virginq.dequeue(virginq.files[0]) + >>> token = str(qmsg['subject']).split()[1].strip() + >>> registrar.confirm(token) + True + + >>> print mlist_2.members.get_member(u'anne@example.com') + <Member: Anne Person <anne@example.com> + on baker@example.com as MemberRole.member> diff --git a/mailman/commands/join.py b/mailman/commands/join.py index 45535470f..639a74a99 100644 --- a/mailman/commands/join.py +++ b/mailman/commands/join.py @@ -69,7 +69,7 @@ example: return ContinueProcessing.no domain = config.domains[mlist.host_name] registrar = IRegistrar(domain) - registrar.register(address, real_name) + registrar.register(address, real_name, mlist) person = formataddr((real_name, address)) print >> results, _('Confirmation email sent to $person') return ContinueProcessing.yes @@ -120,70 +120,6 @@ example: return address, delivery_mode -def ignore(): - # Fill in empty defaults - if digest is None: - digest = mlist.digest_is_default - if password is None: - password = Utils.MakeRandomPassword() - if address is None: - realname, address = parseaddr(res.msg['from']) - if not address: - # Fall back to the sender address - address = res.msg.get_sender() - if not address: - res.results.append(_('No valid address found to subscribe')) - return STOP - # Watch for encoded names - try: - h = make_header(decode_header(realname)) - # BAW: in Python 2.2, use just unicode(h) - realname = h.__unicode__() - except UnicodeError: - realname = u'' - # Coerce to byte string if uh contains only ascii - try: - realname = realname.encode('us-ascii') - except UnicodeError: - pass - # Create the UserDesc record and do a non-approved subscription - listowner = mlist.GetOwnerEmail() - userdesc = UserDesc(address, realname, password, digest) - remote = res.msg.get_sender() - try: - mlist.AddMember(userdesc, remote) - except Errors.MembershipIsBanned: - res.results.append(_("""\ -The email address you supplied is banned from this mailing list. -If you think this restriction is erroneous, please contact the list -owners at %(listowner)s.""")) - return STOP - except Errors.InvalidEmailAddress: - res.results.append(_("""\ -Mailman won't accept the given email address as a valid address.""")) - return STOP - except Errors.MMAlreadyAMember: - res.results.append(_('You are already subscribed!')) - return STOP - except Errors.MMCantDigestError: - res.results.append( - _('No one can subscribe to the digest of this list!')) - return STOP - except Errors.MMMustDigestError: - res.results.append(_('This list only supports digest subscriptions!')) - return STOP - except Errors.MMSubscribeNeedsConfirmation: - # We don't need to respond /and/ send a confirmation message. - res.respond = 0 - except Errors.MMNeedApproval: - res.results.append(_("""\ -Your subscription request has been forwarded to the list administrator -at %(listowner)s for review.""")) - else: - # Everything is a-ok - res.results.append(_('Subscription request succeeded.')) - - class Subscribe(Join): """The email 'subscribe' command (an alias for 'join').""" diff --git a/mailman/docs/registration.txt b/mailman/docs/registration.txt index 2e3ef23e5..73fb149e6 100644 --- a/mailman/docs/registration.txt +++ b/mailman/docs/registration.txt @@ -242,27 +242,12 @@ confirmation step is completed. >>> usermgr.get_address(u'cperson@example.com') <Address: cperson@example.com [verified] at ...> -If an address being registered has already been verified, linked or not to a -user, then registration sends no confirmation. +Even if the address being registered has already been verified, the +registration sends a confirmation. - >>> print registrar.register(u'cperson@example.com') - None - >>> len(switchboard.files) - 0 - -But if the already verified address is not linked to a user, then a user is -created now and they are linked, with no confirmation necessary. - - >>> address = usermgr.create_address(u'dperson@example.com', u'Dave Person') - >>> address.verified_on = datetime.now() - >>> print usermgr.get_user(u'dperson@example.com') - None - >>> print registrar.register(u'dperson@example.com') - None - >>> len(switchboard.files) - 0 - >>> usermgr.get_user(u'dperson@example.com') - <User "Dave Person" at ...> + >>> token = registrar.register(u'cperson@example.com') + >>> token is not None + True Discarding @@ -290,9 +275,12 @@ When a new address for an existing user is registered, there isn't too much different except that the new address will still need to be verified before it can be used. - >>> dperson = usermgr.get_user(u'dperson@example.com') + >>> dperson = usermgr.create_user(u'dperson@example.com', u'Dave Person') >>> dperson <User "Dave Person" at ...> + >>> address = usermgr.get_address(u'dperson@example.com') + >>> address.verified_on = datetime.now() + >>> from operator import attrgetter >>> sorted((addr for addr in dperson.addresses), key=attrgetter('address')) [<Address: Dave Person <dperson@example.com> [verified] at ...>] @@ -339,12 +327,27 @@ pending even matched with that token will still be removed. >>> print pendingdb.confirm(token) None -If somehow the pending registration event doesn't have an address in its -record, you will also get None back, and the record will be removed. - >>> pendable = SimplePendable(type='registration', foo='bar') - >>> token = pendingdb.add(pendable) - >>> registrar.confirm(token) - False - >>> print pendingdb.confirm(token) +Registration and subscription +----------------------------- + +Fred registers with Mailman at the same time that he subscribes to a mailing +list. + + >>> from mailman.app.lifecycle import create_list + >>> mlist = create_list(u'alpha@example.com') + >>> token = registrar.register( + ... u'fred.person@example.com', 'Fred Person', mlist) + +Before confirmation, Fred is not a member of the mailing list. + + >>> print mlist.members.get_member(u'fred.person@example.com') None + +But after confirmation, he is. + + >>> registrar.confirm(token) + True + >>> print mlist.members.get_member(u'fred.person@example.com') + <Member: Fred Person <fred.person@example.com> + on alpha@example.com as MemberRole.member> diff --git a/mailman/interfaces/registrar.py b/mailman/interfaces/registrar.py index bfa02e04d..b7807dac6 100644 --- a/mailman/interfaces/registrar.py +++ b/mailman/interfaces/registrar.py @@ -34,7 +34,7 @@ class IRegistrar(Interface): syntax checking, or confirmation, while this interface does. """ - def register(address, real_name=None): + def register(address, real_name=None, mlist=None): """Register the email address, requesting verification. No IAddress or IUser is created during this step, but after successful |
