Revision: 8221
http://svn.sourceforge.net/mailman/?rev=8221&view=rev
Author: bwarsaw
Date: 2007-05-19 16:27:17 -0700 (Sat, 19 May 2007)
Log Message:
-----------
Many updates to flesh out users, profiles, and addresses:
- Added Elixir-based implementations for IUser and IProfile. Link IAddresses
and IUsers. IUsers can have many IAddresses, but IAddresses may only be
linked to one IUser.
- Change the names of some of the methods in the IProfile interface. Remove
the posting_permission attribute, since posting permissions are not really
preferences.
- Add to IUserManager the following methods: create_user(), delete_user(),
get_user(), and the users attribute. IUserManagers now manage both users
and addresses (which I may want to change since that's a little icky).
- Delete from IUser the user_id attribute. Change the default_profile
attribute to 'profile'. Remove the add_address() and remove_address()
methods. Add a link() and unlink() method. Now IAddresses are created by
an IRoster and linked or unlinked to IUsers.
- Added a generate IManager interface, though this is currently unused and may
go away.
- Remove the IDeliveryMode interfaces. Use the DeliveryMode enum instead.
- Remove the IMember interface. This is essentially what IUser has become.
- Remove the IDeliveryStatus interface. Use the DeliveryStatus enum instead.
- Added doctests for users, and the interaction between users, profiles, and
addresses.
- Remove the calls to objectstore.flush() from model objects. The database
must now be flushed explicitly. Added flush() calls to doctests as
necessary. I still need to work out the transaction model, and make it work
with MailLists, but this can come later.
- Added several exceptions for the new interfaces.
- Added an EnumType converter for SQLAlchemy so that Enums can be properly
stored and retrieved from the database.
- Updated the munepy package to version 1.1. We need Enums to implement
equality comparisons for use with SA's ORM. Still, don't implement ordered
comparisons (== uses 'is' and != uses 'not is').
- Rip some non-working crap out of the inmemory.py file. This really needs to
be rethought.
Modified Paths:
--------------
branches/exp-elixir-branch/Mailman/Errors.py
branches/exp-elixir-branch/Mailman/database/__init__.py
branches/exp-elixir-branch/Mailman/database/model/__init__.py
branches/exp-elixir-branch/Mailman/database/model/address.py
branches/exp-elixir-branch/Mailman/database/usermanager.py
branches/exp-elixir-branch/Mailman/docs/addresses.txt
branches/exp-elixir-branch/Mailman/interfaces/profile.py
branches/exp-elixir-branch/Mailman/interfaces/user.py
branches/exp-elixir-branch/Mailman/interfaces/usermanager.py
branches/exp-elixir-branch/Mailman/testing/inmemory.py
branches/exp-elixir-branch/misc/Makefile.in
Added Paths:
-----------
branches/exp-elixir-branch/Mailman/constants.py
branches/exp-elixir-branch/Mailman/database/model/profile.py
branches/exp-elixir-branch/Mailman/database/model/user.py
branches/exp-elixir-branch/Mailman/database/types.py
branches/exp-elixir-branch/Mailman/docs/users.txt
branches/exp-elixir-branch/Mailman/interfaces/manager.py
branches/exp-elixir-branch/Mailman/testing/test_user.py
branches/exp-elixir-branch/misc/munepy-1.1-py2.5.egg
Removed Paths:
-------------
branches/exp-elixir-branch/Mailman/interfaces/deliverymode.py
branches/exp-elixir-branch/Mailman/interfaces/deliverystatus.py
branches/exp-elixir-branch/Mailman/interfaces/member.py
branches/exp-elixir-branch/misc/munepy-1.0-py2.5.egg
Modified: branches/exp-elixir-branch/Mailman/Errors.py
===================================================================
--- branches/exp-elixir-branch/Mailman/Errors.py 2007-05-18 00:14:58 UTC
(rev 8220)
+++ branches/exp-elixir-branch/Mailman/Errors.py 2007-05-19 23:27:17 UTC
(rev 8221)
@@ -231,6 +231,18 @@
"""The named roster does not exist."""
-class ExistingAddressError(RosterError):
+
+class AddressError(MailmanError):
+ """A general address-related error occurred."""
+
+
+class ExistingAddressError(AddressError):
"""The given email address already exists."""
+
+class AddressAlreadyLinkedError(AddressError):
+ """The address is already linked to a user."""
+
+
+class AddressNotLinkedError(AddressError):
+ """The address is not linked to the user."""
Added: branches/exp-elixir-branch/Mailman/constants.py
===================================================================
--- branches/exp-elixir-branch/Mailman/constants.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/constants.py 2007-05-19 23:27:17 UTC
(rev 8221)
@@ -0,0 +1,44 @@
+# Copyright (C) 2006-2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Various constants and enumerations."""
+
+from munepy import Enum
+
+
+
+class DeliveryMode(Enum):
+ # Regular (i.e. non-digest) delivery
+ regular = 1
+ # Plain text digest delivery
+ plaintext_digests = 2
+ # MIME digest delivery
+ mime_digests = 3
+ # Summary digests
+ summary_digests = 4
+
+
+
+class DeliveryStatus(Enum):
+ # Delivery is enabled
+ enabled = 1
+ # Delivery was disabled by the user
+ by_user = 2
+ # Delivery was disabled due to bouncing addresses
+ by_bounces = 3
+ # Delivery was disabled by an administrator or moderator
+ by_moderator = 4
Modified: branches/exp-elixir-branch/Mailman/database/__init__.py
===================================================================
--- branches/exp-elixir-branch/Mailman/database/__init__.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/database/__init__.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -19,10 +19,17 @@
import os
+from elixir import objectstore
+
from Mailman.database.listmanager import ListManager
from Mailman.database.usermanager import UserManager
+__all__ = [
+ 'initialize',
+ 'flush',
+ ]
+
def initialize():
from Mailman.LockFile import LockFile
@@ -35,3 +42,8 @@
model.initialize()
config.list_manager = ListManager()
config.user_manager = UserManager()
+ flush()
+
+
+def flush():
+ objectstore.flush()
Modified: branches/exp-elixir-branch/Mailman/database/model/__init__.py
===================================================================
--- branches/exp-elixir-branch/Mailman/database/model/__init__.py
2007-05-18 00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/database/model/__init__.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -20,6 +20,7 @@
'Language',
'MailingList',
'Roster',
+ 'User',
'Version',
]
@@ -35,12 +36,15 @@
elixir.delay_setup = True
+from Mailman import constants
from Mailman.Errors import SchemaVersionMismatchError
from Mailman.configuration import config
from Mailman.database.model.address import Address
from Mailman.database.model.language import Language
from Mailman.database.model.mailinglist import MailingList
+from Mailman.database.model.profile import Profile
from Mailman.database.model.roster import Roster
+from Mailman.database.model.user import User
from Mailman.database.model.version import Version
Modified: branches/exp-elixir-branch/Mailman/database/model/address.py
===================================================================
--- branches/exp-elixir-branch/Mailman/database/model/address.py
2007-05-18 00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/database/model/address.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -33,6 +33,7 @@
# Relationships
has_and_belongs_to_many('rosters',
of_kind='Mailman.database.model.roster.Roster')
+ belongs_to('user', of_kind='Mailman.database.model.user.User')
def __str__(self):
return formataddr((self.real_name, self.address))
Copied: branches/exp-elixir-branch/Mailman/database/model/profile.py (from rev
8220, branches/exp-elixir-branch/Mailman/database/model/address.py)
===================================================================
--- branches/exp-elixir-branch/Mailman/database/model/profile.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/database/model/profile.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -0,0 +1,46 @@
+# Copyright (C) 2006-2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+from elixir import *
+from email.utils import formataddr
+from zope.interface import implements
+
+from Mailman.constants import DeliveryMode
+from Mailman.database.types import EnumType
+from Mailman.interfaces import IProfile
+
+
+class Profile(Entity):
+ implements(IProfile)
+
+ has_field('acknowledge_posts', Boolean)
+ has_field('hide_address', Boolean)
+ has_field('preferred_language', Unicode)
+ has_field('receive_list_copy', Boolean)
+ has_field('receive_own_postings', Boolean)
+ has_field('delivery_mode', EnumType)
+ # Relationships
+ belongs_to('user', of_kind='Mailman.database.model.user.User')
+
+ def __init__(self):
+ super(Profile, self).__init__()
+ self.acknowledge_posts = False
+ self.hide_address = True
+ self.preferred_language = 'en'
+ self.receive_list_copy = True
+ self.receive_own_postings = True
+ self.delivery_mode = DeliveryMode.regular
Copied: branches/exp-elixir-branch/Mailman/database/model/user.py (from rev
8220, branches/exp-elixir-branch/Mailman/database/model/address.py)
===================================================================
--- branches/exp-elixir-branch/Mailman/database/model/user.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/database/model/user.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -0,0 +1,50 @@
+# Copyright (C) 2006-2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+from elixir import *
+from email.utils import formataddr
+from zope.interface import implements
+
+from Mailman import Errors
+from Mailman.database.model import Address
+from Mailman.interfaces import IUser
+
+
+class User(Entity):
+ implements(IUser)
+
+ has_field('real_name', Unicode)
+ has_field('password', Unicode)
+ # Relationships
+ has_one('profile', of_kind='Mailman.database.model.profile.Profile')
+ has_many('addresses', of_kind='Mailman.database.model.address.Address')
+
+ def link(self, address):
+ if address.user is not None:
+ raise Errors.AddressAlreadyLinkedError(address)
+ address.user = self
+ self.addresses.append(address)
+
+ def unlink(self, address):
+ if address.user is None:
+ raise Errors.AddressNotLinkedError(address)
+ address.user = None
+ self.addresses.remove(address)
+
+ def controls(self, address):
+ found = Address.get_by(address=address.address)
+ return bool(found and found.user is self)
Added: branches/exp-elixir-branch/Mailman/database/types.py
===================================================================
--- branches/exp-elixir-branch/Mailman/database/types.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/database/types.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -0,0 +1,40 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+import sys
+
+from sqlalchemy import types
+
+
+
+# SQLAlchemy custom type for storing enums in the database.
+class EnumType(types.TypeDecorator):
+ # Enums can be stored as strings of the form:
+ # full.path.to.Enum:intval
+ impl = types.String
+
+ def convert_bind_param(self, value, engine):
+ return '%s:%s.%d' % (value.enumclass.__module__,
+ value.enumclass.__name__,
+ int(value))
+
+ def convert_result_value(self, value, engine):
+ path, intvalue = value.rsplit(':', 1)
+ modulename, classname = intvalue.rsplit('.', 1)
+ __import__(modulename)
+ cls = getattr(sys.modules[modulename], classname)
+ return cls[int(intvalue)]
Modified: branches/exp-elixir-branch/Mailman/database/usermanager.py
===================================================================
--- branches/exp-elixir-branch/Mailman/database/usermanager.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/database/usermanager.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -27,7 +27,10 @@
from Mailman import Errors
from Mailman.LockFile import LockFile
from Mailman.configuration import config
+from Mailman.database.model import Address
+from Mailman.database.model import Profile
from Mailman.database.model import Roster
+from Mailman.database.model import User
from Mailman.interfaces import IUserManager
@@ -49,9 +52,7 @@
roster = Roster.get_by(name=name)
if roster:
raise Errors.RosterExistsError(name)
- roster = Roster(name=name)
- objectstore.flush()
- return roster
+ return Roster(name=name)
def get_roster(self, name):
roster = Roster.get_by(name=name)
@@ -61,9 +62,27 @@
def delete_roster(self, roster):
roster.delete()
- objectstore.flush()
@property
def rosters(self):
for roster in Roster.select():
yield roster
+
+ def create_user(self):
+ user = User()
+ # Users always have a profile
+ user.profile = Profile()
+ user.profile.user = user
+ return user
+
+ def delete_user(self, user):
+ user.delete()
+
+ @property
+ def users(self):
+ for user in User.select():
+ yield user
+
+ def get_user(self, address):
+ found = Address.get_by(address=address)
+ return found and found.user
Modified: branches/exp-elixir-branch/Mailman/docs/addresses.txt
===================================================================
--- branches/exp-elixir-branch/Mailman/docs/addresses.txt 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/docs/addresses.txt 2007-05-19
23:27:17 UTC (rev 8221)
@@ -15,6 +15,7 @@
new roster.
>>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
>>> mgr = config.user_manager
>>> roster_1 = mgr.create_roster('roster-1')
>>> sorted(roster_1.addresses)
@@ -27,6 +28,7 @@
Creating a simple email address object is straight forward.
>>> addr_1 = roster_1.create('[EMAIL PROTECTED]')
+ >>> flush()
>>> addr_1.address
'[EMAIL PROTECTED]'
>>> addr_1.real_name is None
@@ -136,5 +138,6 @@
>>> for roster in mgr.rosters:
... mgr.delete_roster(roster)
+ >>> flush()
>>> list(mgr.rosters)
[]
Added: branches/exp-elixir-branch/Mailman/docs/users.txt
===================================================================
--- branches/exp-elixir-branch/Mailman/docs/users.txt
(rev 0)
+++ branches/exp-elixir-branch/Mailman/docs/users.txt 2007-05-19 23:27:17 UTC
(rev 8221)
@@ -0,0 +1,180 @@
+Users
+=====
+
+Users are entities that combine addresses, preferences, and a password
+scheme. Password schemes can be anything from a traditional
+challenge/response type password string to an OpenID url.
+
+
+Create, deleting, and managing users
+------------------------------------
+
+Users are managed by the IUserManager. Users don't have any unique
+identifying information, and no such id is needed to create them.
+
+ >>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
+ >>> mgr = config.user_manager
+ >>> user = mgr.create_user()
+
+Users have a real name, a password scheme, a default profile, and a set of
+addresses that they control. All of these data are None or empty for a newly
+created user.
+
+ >>> user.real_name is None
+ True
+ >>> user.password is None
+ True
+ >>> user.addresses
+ []
+
+You can iterate over all the users in a user manager.
+
+ >>> another_user = mgr.create_user()
+ >>> flush()
+ >>> all_users = list(mgr.users)
+ >>> len(list(all_users))
+ 2
+ >>> user is not another_user
+ True
+ >>> user in all_users
+ True
+ >>> another_user in all_users
+ True
+
+You can also delete users from the user manager.
+
+ >>> mgr.delete_user(user)
+ >>> mgr.delete_user(another_user)
+ >>> flush()
+ >>> len(list(mgr.users))
+ 0
+
+
+Simple user information
+-----------------------
+
+Users may have a real name and a password scheme.
+
+ >>> user = mgr.create_user()
+ >>> user.password = 'my password'
+ >>> user.real_name = 'Zoe Person'
+ >>> flush()
+ >>> only_person = list(mgr.users)[0]
+ >>> only_person.password
+ 'my password'
+ >>> only_person.real_name
+ 'Zoe Person'
+
+The password and real name can be changed at any time.
+
+ >>> user.real_name = 'Zoe X. Person'
+ >>> user.password = 'another password'
+ >>> only_person.real_name
+ 'Zoe X. Person'
+ >>> only_person.password
+ 'another password'
+
+
+Users and addresses
+-------------------
+
+One of the pieces of information that a user links to is a set of email
+addresses, in the form of IAddress objects. A user can control many
+addresses, but addresses may be control by only one user.
+
+Given a user and an address, you can link the two together.
+
+ >>> roster = mgr.get_roster('')
+ >>> address = roster.create('[EMAIL PROTECTED]', 'Anne Person')
+ >>> user.link(address)
+ >>> flush()
+ >>> sorted(address.address for address in user.addresses)
+ ['[EMAIL PROTECTED]']
+
+But don't try to link an address to more than one user.
+
+ >>> another_user = mgr.create_user()
+ >>> another_user.link(address)
+ Traceback (most recent call last):
+ ...
+ AddressAlreadyLinkedError: Anne Person <[EMAIL PROTECTED]>
+
+You can also ask whether a given user controls a given address.
+
+ >>> user.controls(address)
+ True
+ >>> not_my_address = roster.create('[EMAIL PROTECTED]', 'Ben Person')
+ >>> user.controls(not_my_address)
+ False
+
+Given a text email address, the user manager can find the user that controls
+that address.
+
+ >>> mgr.get_user('[EMAIL PROTECTED]') is user
+ True
+ >>> mgr.get_user('[EMAIL PROTECTED]') is None
+ True
+
+Addresses can also be unlinked from a user.
+
+ >>> user.unlink(address)
+ >>> user.controls(address)
+ False
+ >>> mgr.get_user('[EMAIL PROTECTED]') is None
+ True
+
+But don't try to unlink the address from a user it's not linked to.
+
+ >>> user.unlink(address)
+ Traceback (most recent call last):
+ ...
+ AddressNotLinkedError: Anne Person <[EMAIL PROTECTED]>
+ >>> another_user.unlink(address)
+ Traceback (most recent call last):
+ ...
+ AddressNotLinkedError: Anne Person <[EMAIL PROTECTED]>
+ >>> mgr.delete_user(another_user)
+
+
+Users and profiles
+------------------
+
+Users always have a default profile.
+
+ >>> from Mailman.interfaces import IProfile
+ >>> IProfile.providedBy(user.profile)
+ True
+
+A profile is a set of preferences such as whether the user wants to receive an
+acknowledgment of all of their posts to a mailing list...
+
+ >>> user.profile.acknowledge_posts
+ False
+
+...whether the user wants to hide their email addresses on web pages and in
+postings to the list...
+
+ >>> user.profile.hide_address
+ True
+
+...the language code for the user's preferred language...
+
+ >>> user.profile.preferred_language
+ 'en'
+
+...whether the user wants to receive the list's copy of a message if they are
+explicitly named in one of the recipient headers...
+
+ >>> user.profile.receive_list_copy
+ True
+
+...whether the user wants to receive a copy of their own postings...
+
+ >>> user.profile.receive_own_postings
+ True
+
+...and the preferred delivery method.
+
+ >>> print user.profile.delivery_mode
+ DeliveryMode.regular
Deleted: branches/exp-elixir-branch/Mailman/interfaces/deliverymode.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/deliverymode.py
2007-05-18 00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/deliverymode.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -1,41 +0,0 @@
-# Copyright (C) 2007 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Marker interfaces for various delivery modes."""
-
-from zope.interface import Interface, Attribute
-
-
-
-class IDeliveryMode(Interface):
- """A generic delivery mode."""
-
-
-class IRegularDelivery(IDeliveryMode):
- """Regular delivery mode."""
-
-
-class IDigestDelivery(IDeliveryMode):
- """Base interface for digest delivery."""
-
-
-class IPlainTextDigestDelivery(IDigestDelivery):
- """Plain text digest delivery mode."""
-
-
-class IMIMEDigestDeliver(IDigestDelivery):
- """MIME digest delivery mode."""
Deleted: branches/exp-elixir-branch/Mailman/interfaces/deliverystatus.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/deliverystatus.py
2007-05-18 00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/deliverystatus.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -1,56 +0,0 @@
-# Copyright (C) 2007 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Interface for various delivery status."""
-
-from zope.interface import Interface, Attribute
-
-
-
-class IDeliveryStatus(Interface):
- """Interface for delivery statuses."""
-
- enabled = Attribute(
- """Boolean specifying whether delivery is enabled or not.""")
-
-
-class IDeliveryDisabledByUser(IDeliveryStatus):
- """Interface for deliveries disabled by the user."""
-
-
-class IDeliveryDisabledByAdministrator(IDeliveryStatus):
- """Interface for deliveries disabled by the list owner or moderator."""
-
- reason = Attribute(
- """The text reason given by the list administrator.""")
-
-
-class IDeliveryDisabledByBounces(IDeliveryStatus):
- """Interface for deliveries disabled due to excessive bounces."""
-
- bounce_info = Attribute(
- """The IBounceInfo statistics.""")
-
-
-class IDeliveryTemporarilySuspended(IDeliveryStatus):
- """Interface for temporarily suspended delivery, e.g. while on vacation."""
-
- start_date = Attribute(
- """Date at which delivery suspension begins.""")
-
- end_date = Attribute(
- """Date at which delivery suspension ends.""")
Added: branches/exp-elixir-branch/Mailman/interfaces/manager.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/manager.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/interfaces/manager.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -0,0 +1,57 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Generic database object manager interface."""
+
+from zope.interface import Interface, Attribute
+
+
+
+class IManaged(Interface):
+ """An object managed by an IManager."""
+
+ name = Attribute("""The name of the managed object.""")
+
+
+
+class IManager(Interface):
+ """Create and manage profiles."""
+
+ def create(name):
+ """Create and return a new IManaged object.
+
+ name is the unique name for this object. Raises
+ ExistingManagedObjectError if an IManaged object with the given name
+ already exists.
+ """
+
+ def get(name):
+ """Return the named IManaged object.
+
+ Raises NoSuchManagedObjectError if the named IManaged object does not
+ exist.
+ """
+
+ def delete(name):
+ """Delete the named IManaged object.
+
+ Raises NoSuchManagedObjectError if the named IManaged object does not
+ exist.
+ """
+
+ iterator = Attribute(
+ """Return an iterator over the all the IManaged objects.""")
Deleted: branches/exp-elixir-branch/Mailman/interfaces/member.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/member.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/member.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -1,38 +0,0 @@
-# Copyright (C) 2007 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Interface for an email address which is a member of a roster."""
-
-from zope.interface import Interface, Attribute
-
-
-
-class IMember(Interface):
- """An email address member of a roster.
-
- Members are considered equal if they have the same address and are a
- member of the same roster.
- """
-
- address = Attribute(
- """Read-only IAddress of this member.""")
-
- roster = Attribute(
- """Read-only IRoster this email address is a member of.""")
-
- profile = Attribute(
- """The IProfile for this member's subscription.""")
Modified: branches/exp-elixir-branch/Mailman/interfaces/profile.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/profile.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/profile.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -24,34 +24,30 @@
class IProfile(Interface):
"""Delivery related information."""
- acknowledge = Attribute(
+ acknowledge_posts = Attribute(
"""Boolean specifying whether to send an acknowledgment receipt for
every posting to the mailing list.
""")
- hide = Attribute(
+ hide_address = Attribute(
"""Boolean specifying whether to hide this email address from fellow
list members.
""")
- language = Attribute(
+ preferred_language = Attribute(
"""Preferred language for interacting with a mailing list.""")
- list_copy = Attribute(
+ receive_list_copy = Attribute(
"""Boolean specifying whether to receive a list copy if the user is
explicitly named in one of the recipient headers.
""")
- own_postings = Attribute(
+ receive_own_postings = Attribute(
"""Boolean specifying whether to receive a list copy of the user's own
postings to the mailing list.
""")
delivery_mode = Attribute(
- """The IDeliveryMode.""")
+ """The preferred delivery mode.
- delivery_status = Attribute(
- """The IDeliveryStatus.""")
-
- posting_permission = Attribute(
- """The IPostingPermission.""")
+ This is an enum constant of the type DeliveryMode.""")
Modified: branches/exp-elixir-branch/Mailman/interfaces/user.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/user.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/user.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -22,38 +22,38 @@
class IUser(Interface):
- """A basic user.
+ """A basic user."""
- Users compare equal if they have the same user_id and are managed by the
- same IUserManager instance.
- """
-
- user_id = Attribute(
- """Read-only IUserManager-wide unique user id.""")
-
real_name = Attribute(
"""This user's Real Name.""")
password = Attribute(
"""This user's password information.""")
- default_profile = Attribute(
+ profile = Attribute(
"""The default IProfile for this user.""")
addresses = Attribute(
"""An iterator over all the IAddresses controlled by this user.""")
- def add_address(address):
- """Add the email address to the set of addresses controlled by this
- user. address must be a text email address.
+ def link(address):
+ """Link this user to the given IAddress.
+
+ Raises AddressAlreadyLinkedError if this IAddress is already linked to
+ another user.
"""
- def remove_address(address):
- """Remove the email address from the set of addresses controlled by
- this user. address must be a text email address.
+ def unlink(address):
+ """Unlink this IAddress from the user.
+
+ Raises AddressNotLinkedError if this address is not linked to this
+ user, either because it's not linked to any user or it's linked to
+ some other user.
"""
def controls(address):
- """Return True if this user controls the given email address,
- otherwise False. address must be a text email address
+ """Determine whether this user controls the given email address.
+
+ 'address' is a text email address. This method returns true if the
+ user controls the given email address, otherwise false.
"""
Modified: branches/exp-elixir-branch/Mailman/interfaces/usermanager.py
===================================================================
--- branches/exp-elixir-branch/Mailman/interfaces/usermanager.py
2007-05-18 00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/interfaces/usermanager.py
2007-05-19 23:27:17 UTC (rev 8221)
@@ -53,3 +53,18 @@
rosters = Attribute(
"""An iterator over all IRosters managed by this user manager.""")
+
+ def create_user():
+ """Create and return an IUser."""
+
+ def delete_user(user):
+ """Delete the given IUser."""
+
+ def get_user(address):
+ """Get the user that controls the given email address, or None.
+
+ 'address' is a text email address.
+ """
+
+ users = Attribute(
+ """An iterator over all the IUsers managed by this user manager.""")
Modified: branches/exp-elixir-branch/Mailman/testing/inmemory.py
===================================================================
--- branches/exp-elixir-branch/Mailman/testing/inmemory.py 2007-05-18
00:14:58 UTC (rev 8220)
+++ branches/exp-elixir-branch/Mailman/testing/inmemory.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -134,65 +134,6 @@
-class RegularDelivery(object):
- implements(IRegularDelivery)
-
-
-class PlainTextDigestDelivery(object):
- implements(IPlainTextDigestDelivery)
-
-
-class MIMEDigestDelivery(object):
- implements(IMIMEDigestDeliver)
-
-
-
-class DeliveryEnabled(object):
- implements(IDeliveryStatus)
-
- @property
- def enabled(self):
- return True
-
-
-class DeliveryDisabled(object):
- implements(IDeliveryStatus)
-
- @property
- def enabled(self):
- return False
-
-
-class DeliveryDisabledByUser(DeliveryDisabled):
- implements(IDeliveryDisabledByUser)
-
-
-class DeliveryDisabledbyAdministrator(DeliveryDisabled):
- implements(IDeliveryDisabledByAdministrator)
-
- reason = u'Unknown'
-
-
-class DeliveryDisabledByBounces(DeliveryDisabled):
- implements(IDeliveryDisabledByBounces)
-
- bounce_info = 'XXX'
-
-
-class DeliveryTemporarilySuspended(object):
- implements(IDeliveryTemporarilySuspended)
-
- def __init__(self, start_date, end_date):
- self.start_date = start_date
- self.end_date = end_date
-
- @property
- def enabled(self):
- now = datetime.datetime.now()
- return not (self.start_date <= now < self.end_date)
-
-
-
class OkayToPost(object):
implements(IPostingPermission)
@@ -201,21 +142,6 @@
-class Profile(object):
- implements(IProfile)
-
- # System defaults
- acknowledge = False
- hide = True
- language = 'en'
- list_copy = True
- own_postings = True
- delivery_mode = RegularDelivery()
- delivery_status = DeliveryEnabled()
- posting_permission = OkayToPost()
-
-
-
class Roster(object):
implements(IRoster)
Copied: branches/exp-elixir-branch/Mailman/testing/test_user.py (from rev 8220,
branches/exp-elixir-branch/Mailman/testing/test_address.py)
===================================================================
--- branches/exp-elixir-branch/Mailman/testing/test_user.py
(rev 0)
+++ branches/exp-elixir-branch/Mailman/testing/test_user.py 2007-05-19
23:27:17 UTC (rev 8221)
@@ -0,0 +1,30 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Doctest harness for testing users."""
+
+import doctest
+import unittest
+
+options = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(doctest.DocFileSuite('../docs/users.txt',
+ optionflags=options))
+ return suite
Modified: branches/exp-elixir-branch/misc/Makefile.in
===================================================================
--- branches/exp-elixir-branch/misc/Makefile.in 2007-05-18 00:14:58 UTC (rev
8220)
+++ branches/exp-elixir-branch/misc/Makefile.in 2007-05-19 23:27:17 UTC (rev
8221)
@@ -64,7 +64,7 @@
EZCMD= $(PYTHONLIBDIR)/bin/easy_install $(EZINSTOPTS)
WSGIREF= wsgiref-0.1.2-py2.4.egg
-MUNEPY= munepy-1.0-py2.5.egg
+MUNEPY= munepy-1.1-py2.5.egg
EZPKGS= $(WSGIREF) $(MUNEPY)
# Modes for directories and executables created by the install
Deleted: branches/exp-elixir-branch/misc/munepy-1.0-py2.5.egg
===================================================================
(Binary files differ)
Added: branches/exp-elixir-branch/misc/munepy-1.1-py2.5.egg
===================================================================
(Binary files differ)
Property changes on: branches/exp-elixir-branch/misc/munepy-1.1-py2.5.egg
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org