summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2011-03-18 15:03:15 -0400
committerBarry Warsaw2011-03-18 15:03:15 -0400
commitd10751e5f93e6357aa11323602ef5840cd5eb5e0 (patch)
tree2d12e6ed14b000156971f1f0e912dc519cb5ac33
parentb81ebbf535e8a53b10d4b0f82ecedd8971314610 (diff)
parentdee26f391da59c68a23f8fb960dff9ebd879e916 (diff)
downloadmailman-d10751e5f93e6357aa11323602ef5840cd5eb5e0.tar.gz
mailman-d10751e5f93e6357aa11323602ef5840cd5eb5e0.tar.zst
mailman-d10751e5f93e6357aa11323602ef5840cd5eb5e0.zip
-rw-r--r--src/mailman/commands/docs/membership.txt4
-rw-r--r--src/mailman/database/mailman.sql7
-rw-r--r--src/mailman/interfaces/user.py3
-rw-r--r--src/mailman/model/docs/addresses.txt2
-rw-r--r--src/mailman/model/docs/membership.txt4
-rw-r--r--src/mailman/model/docs/registration.txt8
-rw-r--r--src/mailman/model/docs/usermanager.txt17
-rw-r--r--src/mailman/model/docs/users.txt18
-rw-r--r--src/mailman/model/user.py9
-rw-r--r--src/mailman/model/usermanager.py26
-rw-r--r--src/mailman/rest/docs/membership.txt2
11 files changed, 79 insertions, 21 deletions
diff --git a/src/mailman/commands/docs/membership.txt b/src/mailman/commands/docs/membership.txt
index 0da7ffadf..851f01514 100644
--- a/src/mailman/commands/docs/membership.txt
+++ b/src/mailman/commands/docs/membership.txt
@@ -185,7 +185,7 @@ Joining a second list
Anne of course, is still registered.
>>> print user_manager.get_user('anne@example.com')
- <User "Anne Person" at ...>
+ <User "Anne Person" (...) at ...>
But she is not a member of the mailing list.
@@ -363,7 +363,7 @@ a user of the system.
Now Bart is a user...
>>> print user_manager.get_user('bart@example.com')
- <User "Bart Person" at ...>
+ <User "Bart Person" (...) at ...>
...and a member of the mailing list.
diff --git a/src/mailman/database/mailman.sql b/src/mailman/database/mailman.sql
index 9d2b015b7..8d5a424a3 100644
--- a/src/mailman/database/mailman.sql
+++ b/src/mailman/database/mailman.sql
@@ -252,10 +252,15 @@ CREATE TABLE user (
id INTEGER NOT NULL,
real_name TEXT,
password TEXT,
+ _user_id TEXT,
preferences_id INTEGER,
PRIMARY KEY (id),
- CONSTRAINT user_preferences_id_fk FOREIGN KEY(preferences_id) REFERENCES preferences (id)
+ CONSTRAINT user_preferences_id_fk
+ FOREIGN KEY(preferences_id)
+ REFERENCES preferences (id)
);
+CREATE INDEX ix_user_user_id ON user (_user_id);
+
CREATE TABLE version (
id INTEGER NOT NULL,
component TEXT,
diff --git a/src/mailman/interfaces/user.py b/src/mailman/interfaces/user.py
index 5e894701f..18655e4d8 100644
--- a/src/mailman/interfaces/user.py
+++ b/src/mailman/interfaces/user.py
@@ -38,6 +38,9 @@ class IUser(Interface):
password = Attribute(
"""This user's password information.""")
+ user_id = Attribute(
+ """The user's unique, random, identifier (sha1 hex digest).""")
+
addresses = Attribute(
"""An iterator over all the `IAddresses` controlled by this user.""")
diff --git a/src/mailman/model/docs/addresses.txt b/src/mailman/model/docs/addresses.txt
index 0ddacb321..fdcc993b5 100644
--- a/src/mailman/model/docs/addresses.txt
+++ b/src/mailman/model/docs/addresses.txt
@@ -89,7 +89,7 @@ And now you can find the associated user.
>>> print user_manager.get_user('bperson@example.com')
None
>>> user_manager.get_user('cperson@example.com')
- <User "Claire Person" at ...>
+ <User "Claire Person" (...) at ...>
Deleting addresses
diff --git a/src/mailman/model/docs/membership.txt b/src/mailman/model/docs/membership.txt
index 00e79d733..2fb66ca82 100644
--- a/src/mailman/model/docs/membership.txt
+++ b/src/mailman/model/docs/membership.txt
@@ -44,7 +44,7 @@ in the user database yet.
>>> user_manager = getUtility(IUserManager)
>>> user_1 = user_manager.create_user('aperson@example.com', 'Anne Person')
>>> print user_1
- <User "Anne Person" at ...>
+ <User "Anne Person" (...) at ...>
We can add Anne as an owner of the mailing list, by creating a member role for
her.
@@ -71,7 +71,7 @@ Bart becomes a moderator of the list.
>>> user_2 = user_manager.create_user('bperson@example.com', 'Bart Person')
>>> print user_2
- <User "Bart Person" at ...>
+ <User "Bart Person" (...) at ...>
>>> address_2 = list(user_2.addresses)[0]
>>> address_2.subscribe(mlist, MemberRole.moderator)
<Member: Bart Person <bperson@example.com>
diff --git a/src/mailman/model/docs/registration.txt b/src/mailman/model/docs/registration.txt
index e92c63f52..d0827d37b 100644
--- a/src/mailman/model/docs/registration.txt
+++ b/src/mailman/model/docs/registration.txt
@@ -186,7 +186,7 @@ an `IUser` linked to this address. The `IAddress` is verified.
<Address: Anne Person <aperson@example.com> [verified] at ...>
>>> found_user = user_manager.get_user('aperson@example.com')
>>> found_user
- <User "Anne Person" at ...>
+ <User "Anne Person" (...) at ...>
>>> found_user.controls(found_address.email)
True
>>> from datetime import datetime
@@ -231,7 +231,7 @@ confirmation step is completed.
>>> registrar.confirm(sent_token)
True
>>> user_manager.get_user('cperson@example.com')
- <User "Claire Person" at ...>
+ <User "Claire Person" (...) at ...>
>>> user_manager.get_address('cperson@example.com')
<Address: cperson@example.com [verified] at ...>
@@ -276,7 +276,7 @@ can be used.
>>> dperson = user_manager.create_user(
... 'dperson@example.com', 'Dave Person')
>>> dperson
- <User "Dave Person" at ...>
+ <User "Dave Person" (...) at ...>
>>> address = user_manager.get_address('dperson@example.com')
>>> address.verified_on = datetime.now()
@@ -297,7 +297,7 @@ can be used.
>>> user is dperson
True
>>> user
- <User "Dave Person" at ...>
+ <User "Dave Person" (...) at ...>
>>> dump_list(repr(address) for address in user.addresses)
<Address: Dave Person <dperson@example.com> [verified] at ...>
<Address: David Person <david.person@example.com> [verified] at ...>
diff --git a/src/mailman/model/docs/usermanager.txt b/src/mailman/model/docs/usermanager.txt
index 7b333248c..8304e659c 100644
--- a/src/mailman/model/docs/usermanager.txt
+++ b/src/mailman/model/docs/usermanager.txt
@@ -118,7 +118,7 @@ that the ``.get_user()`` method takes a string email address, not an
>>> address = list(user_4.addresses)[0]
>>> found_user = user_manager.get_user(address.email)
>>> found_user
- <User "Dan Person" at ...>
+ <User "Dan Person" (...) at ...>
>>> found_user is user_4
True
@@ -130,3 +130,18 @@ with it, you will get ``None`` back.
>>> user_4.unlink(address)
>>> print user_manager.get_user(address.email)
None
+
+Users can also be found by their unique user id.
+
+ >>> found_user = user_manager.get_user_by_id(user_4.user_id)
+ >>> user_4
+ <User "Dan Person" (...) at ...>
+ >>> found_user
+ <User "Dan Person" (...) at ...>
+ >>> user_4.user_id == found_user.user_id
+ True
+
+If a non-existent user id is given, None is returned.
+
+ >>> print user_manager.get_user_by_id('missing')
+ None
diff --git a/src/mailman/model/docs/users.txt b/src/mailman/model/docs/users.txt
index bbfef8391..1703db1ee 100644
--- a/src/mailman/model/docs/users.txt
+++ b/src/mailman/model/docs/users.txt
@@ -36,6 +36,24 @@ The password and real name can be changed at any time.
another password
+User id
+=======
+
+Although rarely visible to users, every user has a unique ID in Mailman, which
+never changes. This ID is generated randomly at the time the user is
+created.
+
+ >>> print len(user_1.user_id)
+ 40
+
+The user id cannot change.
+
+ >>> user_1.user_id = 'foo'
+ Traceback (most recent call last):
+ ...
+ AttributeError: can't set attribute
+
+
Users addresses
===============
diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py
index f2a7c9d18..f037bdd48 100644
--- a/src/mailman/model/user.py
+++ b/src/mailman/model/user.py
@@ -46,13 +46,20 @@ class User(Model):
id = Int(primary=True)
real_name = Unicode()
password = Unicode()
+ _user_id = Unicode()
addresses = ReferenceSet(id, 'Address.user_id')
preferences_id = Int()
preferences = Reference(preferences_id, 'Preferences.id')
def __repr__(self):
- return '<User "{0}" at {1:#x}>'.format(self.real_name, id(self))
+ return '<User "{0.real_name}" ({0.user_id}) at {1:#x}>'.format(
+ self, id(self))
+
+ @property
+ def user_id(self):
+ """See `IUser`."""
+ return self._user_id
def link(self, address):
"""See `IUser`."""
diff --git a/src/mailman/model/usermanager.py b/src/mailman/model/usermanager.py
index 067ed7795..3294b3e7f 100644
--- a/src/mailman/model/usermanager.py
+++ b/src/mailman/model/usermanager.py
@@ -25,6 +25,10 @@ __all__ = [
]
+import os
+import time
+import hashlib
+
from zope.interface import implements
from mailman.config import config
@@ -33,6 +37,7 @@ from mailman.interfaces.usermanager import IUserManager
from mailman.model.address import Address
from mailman.model.preferences import Preferences
from mailman.model.user import User
+from mailman.utilities.passwords import SALT_LENGTH
@@ -46,6 +51,11 @@ class UserManager:
address = self.create_address(email, real_name)
user.link(address)
user.preferences = Preferences()
+ # Generate a unique random SHA1 hash for the user id.
+ salt = os.urandom(SALT_LENGTH)
+ h = hashlib.sha1(repr(time.time()))
+ h.update(salt)
+ user._user_id = unicode(h.hexdigest(), 'us-ascii')
config.db.store.add(user)
return user
@@ -56,10 +66,13 @@ class UserManager:
addresses = config.db.store.find(Address, email=email.lower())
if addresses.count() == 0:
return None
- elif addresses.count() == 1:
- return addresses[0].user
- else:
- raise AssertionError('Unexpected query count')
+ return addresses.one().user
+
+ def get_user_by_id(self, user_id):
+ users = config.db.store.find(User, _user_id=user_id)
+ if users.count() == 0:
+ return None
+ return users.one()
@property
def users(self):
@@ -92,10 +105,7 @@ class UserManager:
addresses = config.db.store.find(Address, email=email.lower())
if addresses.count() == 0:
return None
- elif addresses.count() == 1:
- return addresses[0]
- else:
- raise AssertionError('Unexpected query count')
+ return addresses.one()
@property
def addresses(self):
diff --git a/src/mailman/rest/docs/membership.txt b/src/mailman/rest/docs/membership.txt
index 553f6fde9..1e4e0414e 100644
--- a/src/mailman/rest/docs/membership.txt
+++ b/src/mailman/rest/docs/membership.txt
@@ -229,7 +229,7 @@ Elly is now a member of the mailing list.
>>> elly = user_manager.get_user('eperson@example.com')
>>> elly
- <User "Elly Person" at ...>
+ <User "Elly Person" (...) at ...>
>>> set(member.mailing_list for member in elly.memberships.members)
set([u'alpha@example.com'])