summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2016-01-06 22:57:06 -0500
committerBarry Warsaw2016-01-06 22:57:06 -0500
commit4c9487d371a3b61de4533a267ee934c86a1b3237 (patch)
tree74e2e03cdc2d74eb309cb66876992b7ab393799c /src
parenta4bbc7c4fcea5596ab9f5a3d82983ddcf6d25909 (diff)
downloadmailman-4c9487d371a3b61de4533a267ee934c86a1b3237.tar.gz
mailman-4c9487d371a3b61de4533a267ee934c86a1b3237.tar.zst
mailman-4c9487d371a3b61de4533a267ee934c86a1b3237.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/subscriptions.py109
-rw-r--r--src/mailman/config/configure.zcml2
-rw-r--r--src/mailman/model/subscriptions.py131
3 files changed, 133 insertions, 109 deletions
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index 8636e399a..e87eb9731 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -18,7 +18,6 @@
"""Handle subscriptions."""
__all__ = [
- 'SubscriptionService',
'SubscriptionWorkflow',
'handle_ListDeletingEvent',
]
@@ -30,15 +29,12 @@ import logging
from email.utils import formataddr
from enum import Enum
from datetime import timedelta
-from mailman.app.membership import delete_member
from mailman.app.workflow import Workflow
from mailman.core.i18n import _
-from mailman.database.transaction import dbconnection
from mailman.email.message import UserNotification
from mailman.interfaces.address import IAddress
from mailman.interfaces.bans import IBanManager
-from mailman.interfaces.listmanager import (
- IListManager, ListDeletingEvent, NoSuchListError)
+from mailman.interfaces.listmanager import ListDeletingEvent
from mailman.interfaces.mailinglist import SubscriptionPolicy
from mailman.interfaces.member import MembershipIsBannedError
from mailman.interfaces.pending import IPendable, IPendings
@@ -47,14 +43,8 @@ from mailman.interfaces.subscriptions import ISubscriptionService, TokenOwner
from mailman.interfaces.user import IUser
from mailman.interfaces.usermanager import IUserManager
from mailman.interfaces.workflow import IWorkflowStateManager
-from mailman.model.address import Address
-from mailman.model.member import Member
-from mailman.model.user import User
from mailman.utilities.datetime import now
from mailman.utilities.i18n import make
-from mailman.utilities.queries import QuerySequence
-from operator import attrgetter
-from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
@@ -334,103 +324,6 @@ class SubscriptionWorkflow(Workflow):
-@implementer(ISubscriptionService)
-class SubscriptionService:
- """Subscription services for the REST API."""
-
- __name__ = 'members'
-
- def get_members(self):
- """See `ISubscriptionService`."""
- # {list_id -> {role -> [members]}}
- by_list = {}
- user_manager = getUtility(IUserManager)
- for member in user_manager.members:
- by_role = by_list.setdefault(member.list_id, {})
- members = by_role.setdefault(member.role.name, [])
- members.append(member)
- # Flatten into single list sorted as per the interface.
- all_members = []
- address_of_member = attrgetter('address.email')
- for list_id in sorted(by_list):
- by_role = by_list[list_id]
- all_members.extend(
- sorted(by_role.get('owner', []), key=address_of_member))
- all_members.extend(
- sorted(by_role.get('moderator', []), key=address_of_member))
- all_members.extend(
- sorted(by_role.get('member', []), key=address_of_member))
- return all_members
-
- @dbconnection
- def get_member(self, store, member_id):
- """See `ISubscriptionService`."""
- members = store.query(Member).filter(Member._member_id == member_id)
- if members.count() == 0:
- return None
- else:
- assert members.count() == 1, 'Too many matching members'
- return members[0]
-
- @dbconnection
- def find_members(self, store, subscriber=None, list_id=None, role=None):
- """See `ISubscriptionService`."""
- # If `subscriber` is a user id, then we'll search for all addresses
- # which are controlled by the user, otherwise we'll just search for
- # the given address.
- if subscriber is None and list_id is None and role is None:
- return []
- order = (Member.list_id, Address.email, Member.role)
- # Querying for the subscriber is the most complicated part, because
- # the parameter can either be an email address or a user id. Start by
- # building two queries, one joined on the member's address, and one
- # joined on the member's user. Add the resulting email address to the
- # selected values to be able to sort on it later on.
- q_address = store.query(Member, Address.email).join(Member._address)
- q_user = store.query(Member, Address.email).join(Member._user)
- if subscriber is not None:
- if isinstance(subscriber, str):
- # subscriber is an email address.
- q_address = q_address.filter(
- Address.email == subscriber.lower())
- q_user = q_user.join(User.addresses).filter(
- Address.email == subscriber.lower())
- else:
- # subscriber is a user id.
- q_address = q_address.join(Address.user).filter(
- User._user_id == subscriber)
- q_user = q_user.join(User._preferred_address).filter(
- User._user_id == subscriber)
- # Add additional filters to both queries.
- if list_id is not None:
- q_address = q_address.filter(Member.list_id == list_id)
- q_user = q_user.filter(Member.list_id == list_id)
- if role is not None:
- q_address = q_address.filter(Member.role == role)
- q_user = q_user.filter(Member.role == role)
- # Do a UNION of the two queries, sort the result and generate Members.
- try:
- query = q_address.union(q_user).order_by(*order).from_self(Member)
- except NoResultFound:
- query = None
- except MultipleResultsFound:
- raise AssertionError('Too many matches')
- return QuerySequence(query)
-
- def __iter__(self):
- for member in self.get_members():
- yield member
-
- def leave(self, list_id, email):
- """See `ISubscriptionService`."""
- mlist = getUtility(IListManager).get_by_list_id(list_id)
- if mlist is None:
- raise NoSuchListError(list_id)
- # XXX for now, no notification or user acknowledgment.
- delete_member(mlist, email, False, False)
-
-
-
def handle_ListDeletingEvent(event):
"""Delete a mailing list's members when the list is being deleted."""
diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml
index a8fa2c119..b717e125f 100644
--- a/src/mailman/config/configure.zcml
+++ b/src/mailman/config/configure.zcml
@@ -106,7 +106,7 @@
<utility
provides="mailman.interfaces.subscriptions.ISubscriptionService"
- factory="mailman.app.subscriptions.SubscriptionService"
+ factory="mailman.model.subscriptions.SubscriptionService"
/>
<utility
diff --git a/src/mailman/model/subscriptions.py b/src/mailman/model/subscriptions.py
new file mode 100644
index 000000000..d1b805ef1
--- /dev/null
+++ b/src/mailman/model/subscriptions.py
@@ -0,0 +1,131 @@
+# Copyright (C) 2016 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman 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 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman 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
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Subscription services."""
+
+__all__ = [
+ 'SubscriptionService',
+ ]
+
+
+from mailman.app.membership import delete_member
+from mailman.database.transaction import dbconnection
+from mailman.interfaces.listmanager import IListManager, NoSuchListError
+from mailman.interfaces.subscriptions import ISubscriptionService
+from mailman.interfaces.usermanager import IUserManager
+from mailman.model.address import Address
+from mailman.model.member import Member
+from mailman.model.user import User
+from mailman.utilities.queries import QuerySequence
+from operator import attrgetter
+from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
+from zope.component import getUtility
+from zope.interface import implementer
+
+
+@implementer(ISubscriptionService)
+class SubscriptionService:
+ """Subscription services for the REST API."""
+
+ __name__ = 'members'
+
+ def get_members(self):
+ """See `ISubscriptionService`."""
+ # {list_id -> {role -> [members]}}
+ by_list = {}
+ user_manager = getUtility(IUserManager)
+ for member in user_manager.members:
+ by_role = by_list.setdefault(member.list_id, {})
+ members = by_role.setdefault(member.role.name, [])
+ members.append(member)
+ # Flatten into single list sorted as per the interface.
+ all_members = []
+ address_of_member = attrgetter('address.email')
+ for list_id in sorted(by_list):
+ by_role = by_list[list_id]
+ all_members.extend(
+ sorted(by_role.get('owner', []), key=address_of_member))
+ all_members.extend(
+ sorted(by_role.get('moderator', []), key=address_of_member))
+ all_members.extend(
+ sorted(by_role.get('member', []), key=address_of_member))
+ return all_members
+
+ @dbconnection
+ def get_member(self, store, member_id):
+ """See `ISubscriptionService`."""
+ members = store.query(Member).filter(Member._member_id == member_id)
+ if members.count() == 0:
+ return None
+ else:
+ assert members.count() == 1, 'Too many matching members'
+ return members[0]
+
+ @dbconnection
+ def find_members(self, store, subscriber=None, list_id=None, role=None):
+ """See `ISubscriptionService`."""
+ # If `subscriber` is a user id, then we'll search for all addresses
+ # which are controlled by the user, otherwise we'll just search for
+ # the given address.
+ if subscriber is None and list_id is None and role is None:
+ return []
+ order = (Member.list_id, Address.email, Member.role)
+ # Querying for the subscriber is the most complicated part, because
+ # the parameter can either be an email address or a user id. Start by
+ # building two queries, one joined on the member's address, and one
+ # joined on the member's user. Add the resulting email address to the
+ # selected values to be able to sort on it later on.
+ q_address = store.query(Member, Address.email).join(Member._address)
+ q_user = store.query(Member, Address.email).join(Member._user)
+ if subscriber is not None:
+ if isinstance(subscriber, str):
+ # subscriber is an email address.
+ q_address = q_address.filter(
+ Address.email == subscriber.lower())
+ q_user = q_user.join(User.addresses).filter(
+ Address.email == subscriber.lower())
+ else:
+ # subscriber is a user id.
+ q_address = q_address.join(Address.user).filter(
+ User._user_id == subscriber)
+ q_user = q_user.join(User._preferred_address).filter(
+ User._user_id == subscriber)
+ # Add additional filters to both queries.
+ if list_id is not None:
+ q_address = q_address.filter(Member.list_id == list_id)
+ q_user = q_user.filter(Member.list_id == list_id)
+ if role is not None:
+ q_address = q_address.filter(Member.role == role)
+ q_user = q_user.filter(Member.role == role)
+ # Do a UNION of the two queries, sort the result and generate Members.
+ try:
+ query = q_address.union(q_user).order_by(*order).from_self(Member)
+ except NoResultFound:
+ query = None
+ return QuerySequence(query)
+
+ def __iter__(self):
+ for member in self.get_members():
+ yield member
+
+ def leave(self, list_id, email):
+ """See `ISubscriptionService`."""
+ mlist = getUtility(IListManager).get_by_list_id(list_id)
+ if mlist is None:
+ raise NoSuchListError(list_id)
+ # XXX for now, no notification or user acknowledgment.
+ delete_member(mlist, email, False, False)