diff options
Diffstat (limited to 'src/mailman/model')
| -rw-r--r-- | src/mailman/model/docs/addresses.txt | 2 | ||||
| -rw-r--r-- | src/mailman/model/docs/membership.txt | 12 | ||||
| -rw-r--r-- | src/mailman/model/docs/registration.txt | 8 | ||||
| -rw-r--r-- | src/mailman/model/docs/requests.txt | 15 | ||||
| -rw-r--r-- | src/mailman/model/docs/usermanager.txt | 19 | ||||
| -rw-r--r-- | src/mailman/model/docs/users.txt | 33 | ||||
| -rw-r--r-- | src/mailman/model/member.py | 5 | ||||
| -rw-r--r-- | src/mailman/model/user.py | 33 | ||||
| -rw-r--r-- | src/mailman/model/usermanager.py | 21 |
9 files changed, 111 insertions, 37 deletions
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..6f5b82622 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> @@ -102,10 +102,16 @@ role. >>> user_3 = user_manager.create_user( ... 'cperson@example.com', 'Cris Person') >>> address_3 = list(user_3.addresses)[0] - >>> address_3.subscribe(mlist, MemberRole.member) + >>> member = address_3.subscribe(mlist, MemberRole.member) + >>> member <Member: Cris Person <cperson@example.com> on test@example.com as MemberRole.member> +Cris's user record can also be retrieved from her member record. + + >>> member.user + <User "Cris Person" (3) at ...> + Cris will be a regular delivery member but not a digest member. >>> dump_members(mlist.members.members) 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/requests.txt b/src/mailman/model/docs/requests.txt index 94c81e1dc..2ff173422 100644 --- a/src/mailman/model/docs/requests.txt +++ b/src/mailman/model/docs/requests.txt @@ -692,15 +692,9 @@ Frank Person is now a member of the mailing list. <Language [en] English (USA)> >>> print member.delivery_mode DeliveryMode.regular - - >>> from mailman.interfaces.usermanager import IUserManager - >>> from zope.component import getUtility - >>> user_manager = getUtility(IUserManager) - - >>> user = user_manager.get_user(member.address.email) - >>> print user.real_name + >>> print member.user.real_name Frank Person - >>> print user.password + >>> print member.user.password {NONE}abcxyz @@ -713,6 +707,11 @@ unsubscription holds can send the list's moderators an immediate notification. :: + + >>> from mailman.interfaces.usermanager import IUserManager + >>> from zope.component import getUtility + >>> user_manager = getUtility(IUserManager) + >>> mlist.admin_immed_notify = False >>> from mailman.interfaces.member import MemberRole >>> user_1 = user_manager.create_user('gperson@example.com') diff --git a/src/mailman/model/docs/usermanager.txt b/src/mailman/model/docs/usermanager.txt index 7b333248c..e427eb63a 100644 --- a/src/mailman/model/docs/usermanager.txt +++ b/src/mailman/model/docs/usermanager.txt @@ -44,7 +44,7 @@ A user can be assigned a real name. A user can be assigned a password. - >>> user.password = 'secret' + >>> user.password = b'secret' >>> dump_list(user.password for user in user_manager.users) secret @@ -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..c8244c506 100644 --- a/src/mailman/model/docs/users.txt +++ b/src/mailman/model/docs/users.txt @@ -3,8 +3,8 @@ Users ===== Users are entities that represent people. A user has a real name and a -password. Optionally a user may have some preferences and a set of addresses -they control. A user also knows which mailing lists they are subscribed to. +optional encoded password. A user may also have an optional preferences and a +set of addresses they control. See `usermanager.txt`_ for examples of how to create, delete, and find users. @@ -19,7 +19,7 @@ User data Users may have a real name and a password. >>> user_1 = user_manager.create_user() - >>> user_1.password = 'my password' + >>> user_1.password = b'my password' >>> user_1.real_name = 'Zoe Person' >>> dump_list(user.real_name for user in user_manager.users) Zoe Person @@ -29,13 +29,38 @@ Users may have a real name and a password. The password and real name can be changed at any time. >>> user_1.real_name = 'Zoe X. Person' - >>> user_1.password = 'another password' + >>> user_1.password = b'another password' >>> dump_list(user.real_name for user in user_manager.users) Zoe X. Person >>> dump_list(user.password for user in user_manager.users) another password +Basic user identification +========================= + +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. + + # The test suite uses a predictable user id. + >>> print user_1.user_id + 1 + +The user id cannot change. + + >>> user_1.user_id = 'foo' + Traceback (most recent call last): + ... + AttributeError: can't set attribute + +User records also have a date on which they where created. + + # The test suite uses a predictable timestamp. + >>> print user_1.created_on + 2005-08-01 07:49:23 + + Users addresses =============== diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py index 5e8619324..d32c586d9 100644 --- a/src/mailman/model/member.py +++ b/src/mailman/model/member.py @@ -35,6 +35,7 @@ from mailman.database.types import Enum from mailman.interfaces.action import Action from mailman.interfaces.listmanager import IListManager from mailman.interfaces.member import IMember, MemberRole +from mailman.interfaces.usermanager import IUserManager @@ -70,6 +71,10 @@ class Member(Model): return '<Member: {0} on {1} as {2}>'.format( self.address, self.mailing_list, self.role) + @property + def user(self): + return getUtility(IUserManager).get_user(self.address.email) + def _lookup(self, preference): pref = getattr(self.preferences, preference) if pref is not None: diff --git a/src/mailman/model/user.py b/src/mailman/model/user.py index f2a7c9d18..f0048c5f4 100644 --- a/src/mailman/model/user.py +++ b/src/mailman/model/user.py @@ -24,7 +24,8 @@ __all__ = [ 'User', ] -from storm.locals import Int, Reference, ReferenceSet, Unicode +from storm.locals import ( + DateTime, Int, RawStr, Reference, ReferenceSet, Unicode) from zope.interface import implements from mailman.config import config @@ -35,6 +36,8 @@ from mailman.interfaces.user import IUser from mailman.model.address import Address from mailman.model.preferences import Preferences from mailman.model.roster import Memberships +from mailman.utilities.datetime import factory as date_factory +from mailman.utilities.uid import factory as uid_factory @@ -45,14 +48,38 @@ class User(Model): id = Int(primary=True) real_name = Unicode() - password = Unicode() + password = RawStr() + _user_id = Unicode() + _created_on = DateTime() addresses = ReferenceSet(id, 'Address.user_id') preferences_id = Int() preferences = Reference(preferences_id, 'Preferences.id') + def __init__(self, real_name=None, preferences=None): + super(User, self).__init__() + self._created_on = date_factory.now() + user_id = uid_factory.new_uid() + assert config.db.store.find(User, _user_id=user_id).count() == 0, ( + 'Duplicate user id {0}'.format(user_id)) + self._user_id = user_id + self.real_name = ('' if real_name is None else real_name) + self.preferences = preferences + config.db.store.add(self) + 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 + + @property + def created_on(self): + """See `IUser`.""" + return self._created_on def link(self, address): """See `IUser`.""" diff --git a/src/mailman/model/usermanager.py b/src/mailman/model/usermanager.py index 067ed7795..d6817021d 100644 --- a/src/mailman/model/usermanager.py +++ b/src/mailman/model/usermanager.py @@ -40,13 +40,10 @@ class UserManager: implements(IUserManager) def create_user(self, email=None, real_name=None): - user = User() - user.real_name = ('' if real_name is None else real_name) + user = User(real_name, Preferences()) if email: address = self.create_address(email, real_name) user.link(address) - user.preferences = Preferences() - config.db.store.add(user) return user def delete_user(self, user): @@ -56,10 +53,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 +92,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): |
