summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2008-09-24 22:22:29 -0400
committerBarry Warsaw2008-09-24 22:22:29 -0400
commitc129b48a91d11fd3fb69666b8109c3a9372b2f8f (patch)
treee63e9d6ffcf552472de3076c0739d4871400e586
parent546825b4ec7a1018bc2182646e8c0433271d1990 (diff)
downloadmailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.tar.gz
mailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.tar.zst
mailman-c129b48a91d11fd3fb69666b8109c3a9372b2f8f.zip
-rw-r--r--mailman/app/registrar.py45
-rw-r--r--mailman/commands/docs/join.txt41
-rw-r--r--mailman/commands/join.py66
-rw-r--r--mailman/docs/registration.txt59
-rw-r--r--mailman/interfaces/registrar.py2
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