diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/commands/docs/membership.txt | 4 | ||||
| -rw-r--r-- | src/mailman/database/mailman.sql | 7 | ||||
| -rw-r--r-- | src/mailman/interfaces/user.py | 3 | ||||
| -rw-r--r-- | src/mailman/model/docs/addresses.txt | 2 | ||||
| -rw-r--r-- | src/mailman/model/docs/membership.txt | 4 | ||||
| -rw-r--r-- | src/mailman/model/docs/registration.txt | 8 | ||||
| -rw-r--r-- | src/mailman/model/docs/usermanager.txt | 17 | ||||
| -rw-r--r-- | src/mailman/model/docs/users.txt | 18 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 9 | ||||
| -rw-r--r-- | src/mailman/model/usermanager.py | 26 | ||||
| -rw-r--r-- | src/mailman/rest/docs/membership.txt | 2 |
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']) |
