summaryrefslogtreecommitdiff
path: root/Mailman/database/model
diff options
context:
space:
mode:
authorBarry Warsaw2007-06-18 10:50:23 -0400
committerBarry Warsaw2007-06-18 10:50:23 -0400
commit511a33778c4195c4abca7c58aa6917e6a77059b6 (patch)
tree5bffc7a5793a8247310294ac86931741e73b1fc5 /Mailman/database/model
parentf0e3b3934d5d458cadd814eeae07277b58650180 (diff)
downloadmailman-511a33778c4195c4abca7c58aa6917e6a77059b6.tar.gz
mailman-511a33778c4195c4abca7c58aa6917e6a77059b6.tar.zst
mailman-511a33778c4195c4abca7c58aa6917e6a77059b6.zip
Remove both the model and interface for RosterSets. These are no longer used
or necessary in the current data model. Convert the test_handlers.py Python test to an acknowledge.txt doctest, and make the Acknowledge.py handler work with the new data model. There are a few XXX comments left in here due to the fact that the web stuff is a total hack in the current branch currently. Added IMailingListWeb methods and properties to the MailingList model class: web_host and script_url(). Work out how IMembers will expose the lookup-order based preferences. By getting the attribute IMember.preferences you can see exactly the preferences overridden by this member. To use the lookup order, use IMember.delivery_mode, IMember.acknowledge_posts, etc. IOW, the IMember interface now provides the properties directly and access through this mechanism supports lookup order with definitive preference values. Also added IMember.unsubscribe() which does the obvious, and IMember.options_url() which is a total hack for providing a url (but not the ultimately right one) for the user's option page. Refactor the model's roster classes. Also added IRoster.get_member() method with efficient queries to return the right results. Make AdministratorRoster.members more efficient due to a better query. Update the membership.txt doctest to eliminate a chance ordering effect, and also to test finding members with .get_member(). The clean up section uses the new .unsubscribe() method.
Diffstat (limited to 'Mailman/database/model')
-rw-r--r--Mailman/database/model/mailinglist.py12
-rw-r--r--Mailman/database/model/member.py35
-rw-r--r--Mailman/database/model/roster.py96
-rw-r--r--Mailman/database/model/rosterset.py41
4 files changed, 93 insertions, 91 deletions
diff --git a/Mailman/database/model/mailinglist.py b/Mailman/database/model/mailinglist.py
index edd2eab0d..4c7492310 100644
--- a/Mailman/database/model/mailinglist.py
+++ b/Mailman/database/model/mailinglist.py
@@ -30,6 +30,7 @@ class MailingList(Entity):
IMailingListAddresses,
IMailingListIdentity,
IMailingListRosters,
+ IMailingListWeb,
)
# List identity
@@ -179,3 +180,14 @@ class MailingList(Entity):
def fqdn_listname(self):
"""See IMailingListIdentity."""
return fqdn_listname(self.list_name, self.host_name)
+
+ @property
+ def web_host(self):
+ """See IMailingListWeb."""
+ return config.domains[self.host_name]
+
+ def script_url(self, target, context=None):
+ """See IMailingListWeb."""
+ # XXX Handle the case for when context is not None; those would be
+ # relative URLs.
+ return self.web_page_url + target + '/' + self.fqdn_listname
diff --git a/Mailman/database/model/member.py b/Mailman/database/model/member.py
index d9562aede..efb72ee11 100644
--- a/Mailman/database/model/member.py
+++ b/Mailman/database/model/member.py
@@ -19,6 +19,7 @@ from elixir import *
from zope.interface import implements
from Mailman.Utils import split_listname
+from Mailman.constants import SystemDefaultPreferences
from Mailman.database.types import EnumType
from Mailman.interfaces import IMember, IPreferences
@@ -42,3 +43,37 @@ class Member(Entity):
def __repr__(self):
return '<Member: %s on %s as %s>' % (
self.address, self.mailing_list, self.role)
+
+ def _lookup(self, preference):
+ pref = getattr(self.preferences, preference)
+ if pref is not None:
+ return pref
+ pref = getattr(self.address.preferences, preference)
+ if pref is not None:
+ return pref
+ if self.address.user:
+ pref = getattr(self.address.user.preferences, preference)
+ if pref is not None:
+ return pref
+ return getattr(SystemDefaultPreferences, preference)
+
+ @property
+ def delivery_mode(self):
+ return self._lookup('delivery_mode')
+
+ @property
+ def acknowledge_posts(self):
+ return self._lookup('acknowledge_posts')
+
+ @property
+ def preferred_language(self):
+ return self._lookup('preferred_language')
+
+ def unsubscribe(self):
+ self.preferences.delete()
+ self.delete()
+
+ @property
+ def options_url(self):
+ # XXX Um, this is definitely wrong
+ return 'http://example.com/' + self.address.address
diff --git a/Mailman/database/model/roster.py b/Mailman/database/model/roster.py
index ee50cddf0..0730d2b4b 100644
--- a/Mailman/database/model/roster.py
+++ b/Mailman/database/model/roster.py
@@ -22,11 +22,12 @@ the ones that fit a particular role. These are used as the member, owner,
moderator, and administrator roster filters.
"""
+from sqlalchemy import *
from zope.interface import implements
from Mailman.constants import DeliveryMode, MemberRole
from Mailman.constants import SystemDefaultPreferences
-from Mailman.database.model import Member
+from Mailman.database.model import Address, Member
from Mailman.interfaces import IRoster
@@ -42,12 +43,16 @@ class AbstractRoster(object):
"""
implements(IRoster)
+ role = None
+
def __init__(self, mlist):
self._mlist = mlist
@property
def members(self):
- raise NotImplementedError
+ for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
+ role=self.role):
+ yield member
@property
def users(self):
@@ -67,21 +72,27 @@ class AbstractRoster(object):
for member in self.members:
yield member.address
+ def get_member(self, address):
+ results = Member.select(
+ and_(Member.c.mailing_list == self._mlist.fqdn_listname,
+ Member.c.role == self.role,
+ Address.c.address == address,
+ Member.c.address_id == Address.c.id))
+ if len(results) == 0:
+ return None
+ elif len(results) == 1:
+ return results[0]
+ else:
+ assert len(results) <= 1, (
+ 'Too many matching member results: %s' % results)
+
class MemberRoster(AbstractRoster):
"""Return all the members of a list."""
name = 'member'
-
- @property
- def members(self):
- # Query for all the Members which have a role of MemberRole.member and
- # are subscribed to this mailing list. XXX we have to use a private
- # data attribute of MailList for now.
- for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
- role=MemberRole.member):
- yield member
+ role = MemberRole.member
@@ -89,15 +100,7 @@ class OwnerRoster(AbstractRoster):
"""Return all the owners of a list."""
name = 'owner'
-
- @property
- def members(self):
- # Query for all the Members which have a role of MemberRole.member and
- # are subscribed to this mailing list. XXX we have to use a private
- # data attribute of MailList for now.
- for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
- role=MemberRole.owner):
- yield member
+ role = MemberRole.owner
@@ -105,15 +108,7 @@ class ModeratorRoster(AbstractRoster):
"""Return all the owners of a list."""
name = 'moderator'
-
- @property
- def members(self):
- # Query for all the Members which have a role of MemberRole.member and
- # are subscribed to this mailing list. XXX we have to use a private
- # data attribute of MailList for now.
- for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
- role=MemberRole.moderator):
- yield member
+ role = MemberRole.moderator
@@ -125,30 +120,31 @@ class AdministratorRoster(AbstractRoster):
@property
def members(self):
# Administrators are defined as the union of the owners and the
- # moderators. Until I figure out a more efficient way of doing this,
- # this will have to do.
- owners = Member.select_by(mailing_list=self._mlist.fqdn_listname,
- role=MemberRole.owner)
- moderators = Member.select_by(mailing_list=self._mlist.fqdn_listname,
- role=MemberRole.moderator)
- members = set(owners)
- members.update(set(moderators))
+ # moderators.
+ members = Member.select(
+ and_(Member.c.mailing_list == self._mlist.fqdn_listname,
+ or_(Member.c.role == MemberRole.owner,
+ Member.c.role == MemberRole.moderator)))
for member in members:
yield member
-
-
-def _delivery_mode(member):
- if member.preferences.delivery_mode is not None:
- return member.preferences.delivery_mode
- if member.address.preferences.delivery_mode is not None:
- return member.address.preferences.delivery_mode
- if (member.address.user and
- member.address.user.preferences.delivery_mode is not None):
- return member.address.user.preferences.delivery_mode
- return SystemDefaultPreferences.delivery_mode
+ def get_member(self, address):
+ results = Member.select(
+ and_(Member.c.mailing_list == self._mlist.fqdn_listname,
+ or_(Member.c.role == MemberRole.moderator,
+ Member.c.role == MemberRole.owner),
+ Address.c.address == address,
+ Member.c.address_id == Address.c.id))
+ if len(results) == 0:
+ return None
+ elif len(results) == 1:
+ return results[0]
+ else:
+ assert len(results) <= 1, (
+ 'Too many matching member results: %s' % results)
+
class RegularMemberRoster(AbstractRoster):
"""Return all the regular delivery members of a list."""
@@ -161,7 +157,7 @@ class RegularMemberRoster(AbstractRoster):
# that have a regular delivery mode.
for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
role=MemberRole.member):
- if _delivery_mode(member) == DeliveryMode.regular:
+ if member.delivery_mode == DeliveryMode.regular:
yield member
@@ -186,5 +182,5 @@ class DigestMemberRoster(AbstractRoster):
# that have one of the digest delivery modes.
for member in Member.select_by(mailing_list=self._mlist.fqdn_listname,
role=MemberRole.member):
- if _delivery_mode(member) in _digest_modes:
+ if member.delivery_mode in _digest_modes:
yield member
diff --git a/Mailman/database/model/rosterset.py b/Mailman/database/model/rosterset.py
deleted file mode 100644
index f84b52c15..000000000
--- a/Mailman/database/model/rosterset.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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 zope.interface import implements
-
-from Mailman.interfaces import IRosterSet
-
-ROSTER_KIND = 'Mailman.database.model.roster.Roster'
-
-
-
-# Internal implementation of roster sets for use with mailing lists. These
-# are owned by the user storage.
-class RosterSet(Entity):
- implements(IRosterSet)
-
- has_field('name', Unicode)
- has_and_belongs_to_many('rosters', of_kind=ROSTER_KIND)
-
- def add(self, roster):
- if roster not in self.rosters:
- self.rosters.append(roster)
-
- def delete(self, roster):
- if roster in self.rosters:
- self.rosters.remove(roster)