summaryrefslogtreecommitdiff
path: root/src/mailman/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/model')
-rw-r--r--src/mailman/model/docs/addresses.txt2
-rw-r--r--src/mailman/model/docs/membership.txt12
-rw-r--r--src/mailman/model/docs/registration.txt8
-rw-r--r--src/mailman/model/docs/requests.txt15
-rw-r--r--src/mailman/model/docs/usermanager.txt19
-rw-r--r--src/mailman/model/docs/users.txt33
-rw-r--r--src/mailman/model/member.py5
-rw-r--r--src/mailman/model/user.py33
-rw-r--r--src/mailman/model/usermanager.py21
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):