diff options
| author | Barry Warsaw | 2007-06-18 10:50:23 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2007-06-18 10:50:23 -0400 |
| commit | 511a33778c4195c4abca7c58aa6917e6a77059b6 (patch) | |
| tree | 5bffc7a5793a8247310294ac86931741e73b1fc5 /Mailman/database/model | |
| parent | f0e3b3934d5d458cadd814eeae07277b58650180 (diff) | |
| download | mailman-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.py | 12 | ||||
| -rw-r--r-- | Mailman/database/model/member.py | 35 | ||||
| -rw-r--r-- | Mailman/database/model/roster.py | 96 | ||||
| -rw-r--r-- | Mailman/database/model/rosterset.py | 41 |
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) |
