summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarshit Bansal2016-04-12 02:58:25 +0530
committerBarry Warsaw2016-04-18 17:13:01 -0400
commit7559ce6dfdf2d569c91fea173968e46d6857d730 (patch)
tree6443ba6deedf2dc315e964e8c9f35bddbd3b2f4b /src
parentd95f5d501623896ab239a94bda0954424a9d3127 (diff)
downloadmailman-7559ce6dfdf2d569c91fea173968e46d6857d730.tar.gz
mailman-7559ce6dfdf2d569c91fea173968e46d6857d730.tar.zst
mailman-7559ce6dfdf2d569c91fea173968e46d6857d730.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/interfaces/subscriptions.py15
-rw-r--r--src/mailman/model/docs/subscriptions.rst55
-rw-r--r--src/mailman/model/subscriptions.py27
-rw-r--r--src/mailman/model/tests/test_subscriptions.py121
4 files changed, 218 insertions, 0 deletions
diff --git a/src/mailman/interfaces/subscriptions.py b/src/mailman/interfaces/subscriptions.py
index 157bf1b62..f712d33f7 100644
--- a/src/mailman/interfaces/subscriptions.py
+++ b/src/mailman/interfaces/subscriptions.py
@@ -162,3 +162,18 @@ class ISubscriptionService(Interface):
:raises NotAMemberError: if the given address is not a member of the
mailing list.
"""
+
+ def unsubscribe_members(list_id, emails):
+ """Unsubscribe a batch of members from a mailing list.
+
+ :param list_id: The list id to operate on.
+ :type list_id: string
+ :param emails: A list of email addresses of the users getting
+ unsubscribed.
+ :type emails: list of strings
+ :return: A two item tuple whose first item is a list of all the
+ successfully unsubscribed email addresses and second item is
+ a list of all unsuccessfull email addresses.
+ :rtype: Tuple
+ :raises NoSuchListError: if the named mailing list does not exist.
+ """
diff --git a/src/mailman/model/docs/subscriptions.rst b/src/mailman/model/docs/subscriptions.rst
index 6237a24b3..deaea36a1 100644
--- a/src/mailman/model/docs/subscriptions.rst
+++ b/src/mailman/model/docs/subscriptions.rst
@@ -209,3 +209,58 @@ Members can be removed via this service.
on bee@example.com as MemberRole.owner>
<Member: Anne Person <anne@example.com>
on cat@example.com as MemberRole.member>
+
+
+Mass Removal
+============
+
+The subscription service can be used to perform mass removals. You are
+required to pass the list id of the respective mailing list and a list
+of email addresses to be removed.
+
+ >>> bart_2 = subscribe(ant, 'Bart')
+ >>> cris_2 = subscribe(ant, 'Cris')
+ >>> for member in service:
+ ... print(member)
+ <Member: Anne Person <aperson@example.com>
+ on ant@example.com as MemberRole.owner>
+ <Member: Bart Person <bperson@example.com>
+ on ant@example.com as MemberRole.moderator>
+ <Member: Anne Person <aperson@example.com>
+ on ant@example.com as MemberRole.member>
+ <Member: Bart Person <bperson@example.com>
+ on ant@example.com as MemberRole.member>
+ <Member: Cris Person <cperson@example.com>
+ on ant@example.com as MemberRole.member>
+ <Member: Bart Person <bperson@example.com>
+ on bee@example.com as MemberRole.owner>
+ <Member: Anne Person <anne@example.com>
+ on cat@example.com as MemberRole.member>
+ >>> len(service.get_members())
+ 7
+ >>> print(service.find_member('bogus@example.com'))
+ None
+ >>> success, fail = service.unsubscribe_members(
+ ... 'ant.example.com', ['aperson@example.com',
+ ... 'cperson@example.com',
+ ... 'bogus@example.com',
+ ... ])
+ >>> dump_list(success)
+ aperson@example.com
+ cperson@example.com
+ >>> dump_list(fail)
+ bogus@example.com
+ >>> for member in service:
+ ... print(member)
+ <Member: Anne Person <aperson@example.com>
+ on ant@example.com as MemberRole.owner>
+ <Member: Bart Person <bperson@example.com>
+ on ant@example.com as MemberRole.moderator>
+ <Member: Bart Person <bperson@example.com>
+ on ant@example.com as MemberRole.member>
+ <Member: Bart Person <bperson@example.com>
+ on bee@example.com as MemberRole.owner>
+ <Member: Anne Person <anne@example.com>
+ on cat@example.com as MemberRole.member>
+ >>> len(service.get_members())
+ 5
diff --git a/src/mailman/model/subscriptions.py b/src/mailman/model/subscriptions.py
index 3d2bcbeb0..301bfd7d9 100644
--- a/src/mailman/model/subscriptions.py
+++ b/src/mailman/model/subscriptions.py
@@ -21,6 +21,7 @@ from mailman import public
from mailman.app.membership import delete_member
from mailman.database.transaction import dbconnection
from mailman.interfaces.listmanager import IListManager, NoSuchListError
+from mailman.interfaces.member import MemberRole
from mailman.interfaces.subscriptions import (
ISubscriptionService, TooManyMembersError)
from mailman.interfaces.usermanager import IUserManager
@@ -146,3 +147,29 @@ class SubscriptionService:
raise NoSuchListError(list_id)
# XXX for now, no notification or user acknowledgment.
delete_member(mlist, email, False, False)
+
+ @dbconnection
+ def unsubscribe_members(self, store, list_id, emails):
+ """See 'ISubscriptionService'."""
+ successful = []
+ unsuccessful = []
+ mlist = getUtility(IListManager).get_by_list_id(list_id)
+ if mlist is None:
+ raise NoSuchListError(list_id)
+ q_mem = store.query(Member).filter(
+ Member.list_id == list_id, Member.role == MemberRole.member)
+ for email in emails:
+ unsubscribed = False
+ q_addr = q_mem.join(Member._address).filter(
+ Address.email == email)
+ q_user = q_mem.join(Member._user).join(
+ User._preferred_address).filter(Address.email == email)
+ members = q_addr.union(q_user).all()
+ for member in members:
+ member.unsubscribe()
+ unsubscribed = True
+ if unsubscribed:
+ successful.append(email)
+ else:
+ unsuccessful.append(email)
+ return successful, unsuccessful
diff --git a/src/mailman/model/tests/test_subscriptions.py b/src/mailman/model/tests/test_subscriptions.py
index 6b884b22f..49db3cf62 100644
--- a/src/mailman/model/tests/test_subscriptions.py
+++ b/src/mailman/model/tests/test_subscriptions.py
@@ -239,3 +239,124 @@ class TestSubscriptionService(unittest.TestCase):
# Trying to leave a nonexistent list raises an exception.
self.assertRaises(NoSuchListError, self._service.leave,
'bogus.example.com', 'anne@example.com')
+
+ def test_unsubscribe_members_no_such_list(self):
+ # Raises an exception if an invalid list_id is passed
+ self.assertRaises(NoSuchListError, self._service.unsubscribe_members,
+ 'bogus.example.com', 'anne@example.com')
+
+ def test_unsubscribe_members(self):
+ # Check that memberships are properly unsubscribed
+ # Create lists for testing.
+ mlist1 = create_list('test1@example.com')
+ mlist1.admin_immed_notify = False
+ mlist2 = create_list('test2@example.com')
+ mlist2.admin_immed_notify = False
+ # Create users and addresses
+ user = self._user_manager.create_user(
+ 'anne1@example.com', 'Anne User')
+ address_1 = set_preferred(user)
+ address_2 = self._user_manager.create_address(
+ 'anne2@example.com', 'Anne User 2')
+ address_2.verified_on = now()
+ address_2.user = user
+ address_3 = self._user_manager.create_address(
+ 'anne3@example.com', 'Anne User 3')
+ address_3.verified_on = now()
+ address_3.user = user
+ address_4 = self._user_manager.create_address(
+ 'addr1@example.com', 'Address 1')
+ address_4.verified_on = now()
+ address_5 = self._user_manager.create_address(
+ 'addr2@example.com', 'Address 2')
+ address_5.verified_on = now()
+ address_6 = self._user_manager.create_address(
+ 'addr3@example.com', 'Address 3')
+ address_6.verified_on = now()
+ user_1 = self._user_manager.create_user(
+ 'user1@example.com', 'User 1')
+ set_preferred(user_1)
+ address_8 = self._user_manager.create_address(
+ 'user2@example.com', 'User 2')
+ address_8.verified_on = now()
+ address_8.user = user_1
+ # Subscribe the addresses to mailing lists
+ mlist1.subscribe(user, MemberRole.member)
+ mlist1.subscribe(user, MemberRole.moderator)
+ mlist1.subscribe(user, MemberRole.owner)
+ mlist1.subscribe(address_1, MemberRole.member)
+ mlist1.subscribe(address_2, MemberRole.member)
+ mlist1.subscribe(address_2, MemberRole.moderator)
+ mlist1.subscribe(address_3, MemberRole.member)
+ mlist1.subscribe(address_4, MemberRole.member)
+ mlist1.subscribe(address_5, MemberRole.member)
+ mlist1.subscribe(address_5, MemberRole.moderator)
+ mlist1.subscribe(address_6, MemberRole.member)
+ mlist1.subscribe(user_1, MemberRole.member)
+ mlist1.subscribe(address_8, MemberRole.member)
+ mlist2.subscribe(user, MemberRole.member)
+ mlist2.subscribe(user, MemberRole.moderator)
+ mlist2.subscribe(address_1, MemberRole.member)
+ mlist2.subscribe(address_1, MemberRole.moderator)
+ mlist2.subscribe(address_2, MemberRole.member)
+ mlist2.subscribe(address_2, MemberRole.owner)
+ mlist2.subscribe(address_4, MemberRole.member)
+ mlist2.subscribe(address_5, MemberRole.member)
+ mlist2.subscribe(address_6, MemberRole.member)
+ mlist2.subscribe(address_6, MemberRole.moderator)
+ # Unsubscribe members from mlist1
+ success, fail = self._service.unsubscribe_members(mlist1.list_id,
+ ['anne1@example.com',
+ 'anne2@example.com',
+ 'addr1@example.com',
+ 'addr2@example.com',
+ 'user2@example.com',
+ 'bogus@example.com',
+ ])
+ self.assertListEqual(success, ['anne1@example.com',
+ 'anne2@example.com',
+ 'addr1@example.com',
+ 'addr2@example.com',
+ 'user2@example.com',
+ ])
+ self.assertListEqual(fail, ['bogus@example.com'])
+ # Obtain rosters
+ members_1 = mlist1.get_roster(MemberRole.member)
+ moderators_1 = mlist1.get_roster(MemberRole.moderator)
+ owners_1 = mlist1.get_roster(MemberRole.owner)
+ members_2 = mlist2.get_roster(MemberRole.member)
+ moderators_2 = mlist2.get_roster(MemberRole.moderator)
+ owners_2 = mlist2.get_roster(MemberRole.owner)
+ self.assertListEqual(
+ [address.email for address in members_1.addresses],
+ ['anne3@example.com',
+ 'addr3@example.com',
+ 'user1@example.com',
+ ])
+ self.assertListEqual(
+ [address.email for address in moderators_1.addresses],
+ ['anne1@example.com',
+ 'anne2@example.com',
+ 'addr2@example.com',
+ ])
+ self.assertListEqual(
+ [address.email for address in owners_1.addresses],
+ ['anne1@example.com'])
+ self.assertListEqual(
+ [address.email for address in members_2.addresses],
+ ['anne1@example.com',
+ 'anne1@example.com',
+ 'anne2@example.com',
+ 'addr1@example.com',
+ 'addr2@example.com',
+ 'addr3@example.com',
+ ])
+ self.assertListEqual(
+ [address.email for address in moderators_2.addresses],
+ ['anne1@example.com',
+ 'anne1@example.com',
+ 'addr3@example.com',
+ ])
+ self.assertListEqual(
+ [address.email for address in owners_2.addresses],
+ ['anne2@example.com'])