summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2012-09-04 21:31:50 -0400
committerBarry Warsaw2012-09-04 21:31:50 -0400
commit3c77c83ec4070e7183482445ff0b9a30398b72f4 (patch)
tree7d992c11114cc2e8cb1c22d65f517c1d1f5f201f /src
parent56c3bf127b5fb912461e638b6936c627d30be744 (diff)
downloadmailman-3c77c83ec4070e7183482445ff0b9a30398b72f4.tar.gz
mailman-3c77c83ec4070e7183482445ff0b9a30398b72f4.tar.zst
mailman-3c77c83ec4070e7183482445ff0b9a30398b72f4.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/bounces.py3
-rw-r--r--src/mailman/app/docs/lifecycle.rst2
-rw-r--r--src/mailman/app/docs/subscriptions.rst24
-rw-r--r--src/mailman/app/events.py2
-rw-r--r--src/mailman/app/lifecycle.py22
-rw-r--r--src/mailman/app/subscriptions.py53
-rw-r--r--src/mailman/app/tests/test_membership.py8
-rw-r--r--src/mailman/app/tests/test_subscriptions.py4
-rw-r--r--src/mailman/commands/cli_lists.py2
-rw-r--r--src/mailman/commands/eml_membership.py2
-rw-r--r--src/mailman/database/schema/mm_20120407000000.py85
-rw-r--r--src/mailman/database/schema/sqlite_20120407000000_01.sql2
-rw-r--r--src/mailman/database/tests/test_migrations.py10
-rw-r--r--src/mailman/docs/NEWS.rst13
-rw-r--r--src/mailman/interfaces/listmanager.py13
-rw-r--r--src/mailman/interfaces/mailinglist.py5
-rw-r--r--src/mailman/interfaces/member.py5
-rw-r--r--src/mailman/interfaces/subscriptions.py26
-rw-r--r--src/mailman/model/docs/listmanager.rst66
-rw-r--r--src/mailman/model/docs/mailinglist.rst11
-rw-r--r--src/mailman/model/docs/membership.rst12
-rw-r--r--src/mailman/model/docs/usermanager.rst11
-rw-r--r--src/mailman/model/docs/users.rst11
-rw-r--r--src/mailman/model/listmanager.py22
-rw-r--r--src/mailman/model/mailinglist.py13
-rw-r--r--src/mailman/model/member.py22
-rw-r--r--src/mailman/model/roster.py14
-rw-r--r--src/mailman/rest/addresses.py2
-rw-r--r--src/mailman/rest/docs/addresses.rst10
-rw-r--r--src/mailman/rest/docs/membership.rst108
-rw-r--r--src/mailman/rest/lists.py4
-rw-r--r--src/mailman/rest/members.py10
-rw-r--r--src/mailman/rest/tests/test_membership.py10
-rw-r--r--src/mailman/styles/default.py1
-rw-r--r--src/mailman/utilities/tests/test_import.py2
35 files changed, 366 insertions, 244 deletions
diff --git a/src/mailman/app/bounces.py b/src/mailman/app/bounces.py
index 0a291d671..41a8f3560 100644
--- a/src/mailman/app/bounces.py
+++ b/src/mailman/app/bounces.py
@@ -192,7 +192,8 @@ def send_probe(member, msg):
:return: The token representing this probe in the pendings database.
:rtype: string
"""
- mlist = getUtility(IListManager).get(member.mailing_list)
+ mlist = getUtility(IListManager).get_by_list_id(
+ member.mailing_list.list_id)
text = make('probe.txt', mlist, member.preferred_language.code,
listname=mlist.fqdn_listname,
address= member.address.email,
diff --git a/src/mailman/app/docs/lifecycle.rst b/src/mailman/app/docs/lifecycle.rst
index 9a3337123..f6bb7ddae 100644
--- a/src/mailman/app/docs/lifecycle.rst
+++ b/src/mailman/app/docs/lifecycle.rst
@@ -140,7 +140,7 @@ artifacts.
::
>>> from mailman.app.lifecycle import remove_list
- >>> remove_list(mlist_2.fqdn_listname, mlist_2)
+ >>> remove_list(mlist_2)
>>> from mailman.interfaces.listmanager import IListManager
>>> from zope.component import getUtility
diff --git a/src/mailman/app/docs/subscriptions.rst b/src/mailman/app/docs/subscriptions.rst
index f897d219e..dd8298cb3 100644
--- a/src/mailman/app/docs/subscriptions.rst
+++ b/src/mailman/app/docs/subscriptions.rst
@@ -30,13 +30,13 @@ role. At a minimum, a mailing list and an address for the new user is
required.
>>> mlist = create_list('test@example.com')
- >>> anne = service.join('test@example.com', 'anne@example.com')
+ >>> anne = service.join('test.example.com', 'anne@example.com')
>>> anne
<Member: anne <anne@example.com> on test@example.com as MemberRole.member>
The real name of the new member can be given.
- >>> bart = service.join('test@example.com', 'bart@example.com',
+ >>> bart = service.join('test.example.com', 'bart@example.com',
... 'Bart Person')
>>> bart
<Member: Bart Person <bart@example.com>
@@ -45,7 +45,7 @@ The real name of the new member can be given.
Other roles can also be subscribed.
>>> from mailman.interfaces.member import MemberRole
- >>> anne_owner = service.join('test@example.com', 'anne@example.com',
+ >>> anne_owner = service.join('test.example.com', 'anne@example.com',
... role=MemberRole.owner)
>>> anne_owner
<Member: anne <anne@example.com> on test@example.com as MemberRole.owner>
@@ -67,7 +67,7 @@ New members can also be added by providing an existing user id instead of an
email address. However, the user must have a preferred email address.
::
- >>> service.join('test@example.com', bart.user.user_id,
+ >>> service.join('test.example.com', bart.user.user_id,
... role=MemberRole.owner)
Traceback (most recent call last):
...
@@ -78,7 +78,7 @@ email address. However, the user must have a preferred email address.
>>> address = list(bart.user.addresses)[0]
>>> address.verified_on = now()
>>> bart.user.preferred_address = address
- >>> service.join('test@example.com', bart.user.user_id,
+ >>> service.join('test.example.com', bart.user.user_id,
... role=MemberRole.owner)
<Member: Bart Person <bart@example.com>
on test@example.com as MemberRole.owner>
@@ -89,7 +89,7 @@ Removing members
Regular members can also be removed.
- >>> cris = service.join('test@example.com', 'cris@example.com')
+ >>> cris = service.join('test.example.com', 'cris@example.com')
>>> service.get_members()
[<Member: anne <anne@example.com> on test@example.com
as MemberRole.owner>,
@@ -103,7 +103,7 @@ Regular members can also be removed.
as MemberRole.member>]
>>> sum(1 for member in service)
5
- >>> service.leave('test@example.com', 'cris@example.com')
+ >>> service.leave('test.example.com', 'cris@example.com')
>>> service.get_members()
[<Member: anne <anne@example.com> on test@example.com
as MemberRole.owner>,
@@ -173,7 +173,7 @@ Memberships can also be searched for by user id.
You can find all the memberships for a specific mailing list.
- >>> service.find_members(fqdn_listname='test@example.com')
+ >>> service.find_members(list_id='test.example.com')
[<Member: anne <anne@example.com> on test@example.com
as MemberRole.member>,
<Member: anne <anne@example.com> on test@example.com as MemberRole.owner>,
@@ -184,9 +184,11 @@ You can find all the memberships for a specific mailing list.
<Member: Bart Person <bart@example.com> on test@example.com
as MemberRole.owner>]
-You can find all the memberships for an address on a specific mailing list.
+You can find all the memberships for an address on a specific mailing list,
+but you have to give it the list id, not the fqdn listname since the former is
+stable but the latter could change if the list is moved.
- >>> service.find_members('anne@example.com', 'test@example.com')
+ >>> service.find_members('anne@example.com', 'test.example.com')
[<Member: anne <anne@example.com> on test@example.com
as MemberRole.member>,
<Member: anne <anne@example.com> on test@example.com
@@ -203,7 +205,7 @@ You can find all the memberships for an address with a specific role.
You can also find a specific membership by all three criteria.
- >>> service.find_members('anne@example.com', 'test@example.com',
+ >>> service.find_members('anne@example.com', 'test.example.com',
... MemberRole.owner)
[<Member: anne <anne@example.com> on test@example.com
as MemberRole.owner>]
diff --git a/src/mailman/app/events.py b/src/mailman/app/events.py
index a4f385239..28d78e001 100644
--- a/src/mailman/app/events.py
+++ b/src/mailman/app/events.py
@@ -41,7 +41,7 @@ def initialize():
domain.handle_DomainDeletingEvent,
moderator.handle_ListDeletingEvent,
passwords.handle_ConfigurationUpdatedEvent,
- subscriptions.handle_ListDeletedEvent,
+ subscriptions.handle_ListDeletingEvent,
switchboard.handle_ConfigurationUpdatedEvent,
i18n.handle_ConfigurationUpdatedEvent,
style_manager.handle_ConfigurationUpdatedEvent,
diff --git a/src/mailman/app/lifecycle.py b/src/mailman/app/lifecycle.py
index 5082034bc..326498478 100644
--- a/src/mailman/app/lifecycle.py
+++ b/src/mailman/app/lifecycle.py
@@ -89,23 +89,19 @@ def create_list(fqdn_listname, owners=None):
-def remove_list(fqdn_listname, mailing_list=None):
+def remove_list(mlist):
"""Remove the list and all associated artifacts and subscriptions."""
+ fqdn_listname = mlist.fqdn_listname
removeables = []
- # mailing_list will be None when only residual archives are being removed.
- if mailing_list is not None:
- # Remove all subscriptions, regardless of role.
- for member in mailing_list.subscribers.members:
- member.unsubscribe()
- # Delete the mailing list from the database.
- getUtility(IListManager).delete(mailing_list)
- # Do the MTA-specific list deletion tasks
- call_name(config.mta.incoming).create(mailing_list)
- # Remove the list directory.
- removeables.append(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
+ # Delete the mailing list from the database.
+ getUtility(IListManager).delete(mlist)
+ # Do the MTA-specific list deletion tasks
+ call_name(config.mta.incoming).delete(mlist)
+ # Remove the list directory.
+ removeables.append(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
# Remove any stale locks associated with the list.
for filename in os.listdir(config.LOCK_DIR):
- fn_listname = filename.split('.')[0]
+ fn_listname, dot, rest = filename.partition('.')
if fn_listname == fqdn_listname:
removeables.append(os.path.join(config.LOCK_DIR, filename))
# Now that we know what files and directories to delete, delete them.
diff --git a/src/mailman/app/subscriptions.py b/src/mailman/app/subscriptions.py
index 7949f83ee..3937d5b5c 100644
--- a/src/mailman/app/subscriptions.py
+++ b/src/mailman/app/subscriptions.py
@@ -22,7 +22,7 @@ from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
'SubscriptionService',
- 'handle_ListDeletedEvent',
+ 'handle_ListDeletingEvent',
]
@@ -39,7 +39,7 @@ from mailman.core.constants import system_preferences
from mailman.database.transaction import dbconnection
from mailman.interfaces.address import IEmailValidator
from mailman.interfaces.listmanager import (
- IListManager, ListDeletedEvent, NoSuchListError)
+ IListManager, ListDeletingEvent, NoSuchListError)
from mailman.interfaces.member import DeliveryMode, MemberRole
from mailman.interfaces.subscriptions import (
ISubscriptionService, MissingUserError)
@@ -49,16 +49,12 @@ from mailman.model.member import Member
def _membership_sort_key(member):
- """Sort function for get_members().
+ """Sort function for find_members().
- The members are sorted first by fully-qualified mailing list name,
- then by subscribed email address, then by role.
+ The members are sorted first by unique list id, then by subscribed email
+ address, then by role.
"""
- # member.mailing_list is already the fqdn_listname, not the IMailingList
- # object.
- return (member.mailing_list,
- member.address.email,
- int(member.role))
+ return (member.list_id, member.address.email, int(member.role))
@@ -70,18 +66,18 @@ class SubscriptionService:
def get_members(self):
"""See `ISubscriptionService`."""
- # {fqdn_listname -> {role -> [members]}}
+ # {list_id -> {role -> [members]}}
by_list = {}
user_manager = getUtility(IUserManager)
for member in user_manager.members:
- by_role = by_list.setdefault(member.mailing_list, {})
+ 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 fqdn_listname in sorted(by_list):
- by_role = by_list[fqdn_listname]
+ 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(
@@ -103,14 +99,13 @@ class SubscriptionService:
return members[0]
@dbconnection
- def find_members(self, store,
- subscriber=None, fqdn_listname=None, role=None):
+ 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.
user_manager = getUtility(IUserManager)
- if subscriber is None and fqdn_listname is None and role is None:
+ if subscriber is None and list_id is None and role is None:
return []
# Querying for the subscriber is the most complicated part, because
# the parameter can either be an email address or a user id.
@@ -136,8 +131,8 @@ class SubscriptionService:
Member.address_id.is_in(address_ids)))
# Calculate the rest of the query expression, which will get And'd
# with the Or clause above (if there is one).
- if fqdn_listname is not None:
- query.append(Member.mailing_list == fqdn_listname)
+ if list_id is not None:
+ query.append(Member.list_id == list_id)
if role is not None:
query.append(Member.role == role)
results = store.find(Member, And(*query))
@@ -147,14 +142,14 @@ class SubscriptionService:
for member in self.get_members():
yield member
- def join(self, fqdn_listname, subscriber,
+ def join(self, list_id, subscriber,
display_name=None,
delivery_mode=DeliveryMode.regular,
role=MemberRole.member):
"""See `ISubscriptionService`."""
- mlist = getUtility(IListManager).get(fqdn_listname)
+ mlist = getUtility(IListManager).get_by_list_id(list_id)
if mlist is None:
- raise NoSuchListError(fqdn_listname)
+ raise NoSuchListError(list_id)
# Is the subscriber an email address or user id?
if isinstance(subscriber, basestring):
# It's an email address, so we'll want a real name. Make sure
@@ -181,23 +176,23 @@ class SubscriptionService:
raise MissingUserError(subscriber)
return mlist.subscribe(user, role)
- def leave(self, fqdn_listname, email):
+ def leave(self, list_id, email):
"""See `ISubscriptionService`."""
- mlist = getUtility(IListManager).get(fqdn_listname)
+ mlist = getUtility(IListManager).get_by_list_id(list_id)
if mlist is None:
- raise NoSuchListError(fqdn_listname)
+ raise NoSuchListError(list_id)
# XXX for now, no notification or user acknowledgment.
delete_member(mlist, email, False, False)
-def handle_ListDeletedEvent(event):
- """Delete a mailing list's members when the list is deleted."""
+def handle_ListDeletingEvent(event):
+ """Delete a mailing list's members when the list is being deleted."""
- if not isinstance(event, ListDeletedEvent):
+ if not isinstance(event, ListDeletingEvent):
return
# Find all the members still associated with the mailing list.
members = getUtility(ISubscriptionService).find_members(
- fqdn_listname=event.fqdn_listname)
+ list_id=event.mailing_list.list_id)
for member in members:
member.unsubscribe()
diff --git a/src/mailman/app/tests/test_membership.py b/src/mailman/app/tests/test_membership.py
index 626be8b08..00c279910 100644
--- a/src/mailman/app/tests/test_membership.py
+++ b/src/mailman/app/tests/test_membership.py
@@ -52,7 +52,7 @@ class AddMemberTest(unittest.TestCase):
'Anne Person', '123', DeliveryMode.regular,
system_preferences.preferred_language)
self.assertEqual(member.address.email, 'aperson@example.com')
- self.assertEqual(member.mailing_list, 'test@example.com')
+ self.assertEqual(member.list_id, 'test.example.com')
self.assertEqual(member.role, MemberRole.member)
def test_add_member_existing_user(self):
@@ -64,7 +64,7 @@ class AddMemberTest(unittest.TestCase):
'Anne Person', '123', DeliveryMode.regular,
system_preferences.preferred_language)
self.assertEqual(member.address.email, 'aperson@example.com')
- self.assertEqual(member.mailing_list, 'test@example.com')
+ self.assertEqual(member.list_id, 'test.example.com')
def test_add_member_banned(self):
# Test that members who are banned by specific address cannot
@@ -127,7 +127,7 @@ class AddMemberTest(unittest.TestCase):
system_preferences.preferred_language,
MemberRole.moderator)
self.assertEqual(member.address.email, 'aperson@example.com')
- self.assertEqual(member.mailing_list, 'test@example.com')
+ self.assertEqual(member.list_id, 'test.example.com')
self.assertEqual(member.role, MemberRole.moderator)
def test_add_member_twice(self):
@@ -159,7 +159,7 @@ class AddMemberTest(unittest.TestCase):
'Anne Person', '123', DeliveryMode.regular,
system_preferences.preferred_language,
MemberRole.owner)
- self.assertEqual(member_1.mailing_list, member_2.mailing_list)
+ self.assertEqual(member_1.list_id, member_2.list_id)
self.assertEqual(member_1.address, member_2.address)
self.assertEqual(member_1.user, member_2.user)
self.assertNotEqual(member_1.member_id, member_2.member_id)
diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py
index a63c9ac04..1c37d4cb9 100644
--- a/src/mailman/app/tests/test_subscriptions.py
+++ b/src/mailman/app/tests/test_subscriptions.py
@@ -52,7 +52,7 @@ class TestJoin(unittest.TestCase):
def test_join_user_with_bogus_id(self):
# When `subscriber` is a missing user id, an exception is raised.
try:
- self._service.join('test@example.com', uuid.UUID(int=99))
+ self._service.join('test.example.com', uuid.UUID(int=99))
except MissingUserError as exc:
self.assertEqual(exc.user_id, uuid.UUID(int=99))
else:
@@ -62,7 +62,7 @@ class TestJoin(unittest.TestCase):
# When `subscriber` is a string that is not an email address, an
# exception is raised.
try:
- self._service.join('test@example.com', 'bogus')
+ self._service.join('test.example.com', 'bogus')
except InvalidEmailAddressError as exc:
self.assertEqual(exc.email, 'bogus')
else:
diff --git a/src/mailman/commands/cli_lists.py b/src/mailman/commands/cli_lists.py
index cf72c51a8..b91f708de 100644
--- a/src/mailman/commands/cli_lists.py
+++ b/src/mailman/commands/cli_lists.py
@@ -274,4 +274,4 @@ class Remove:
return
else:
log(_('Removed list: $fqdn_listname'))
- remove_list(fqdn_listname, mlist)
+ remove_list(mlist)
diff --git a/src/mailman/commands/eml_membership.py b/src/mailman/commands/eml_membership.py
index 860e42f47..63efbafca 100644
--- a/src/mailman/commands/eml_membership.py
+++ b/src/mailman/commands/eml_membership.py
@@ -84,7 +84,7 @@ used.
# Is this person already a member of the list? Search for all
# matching memberships.
members = getUtility(ISubscriptionService).find_members(
- address, mlist.fqdn_listname, MemberRole.member)
+ address, mlist.list_id, MemberRole.member)
if len(members) > 0:
print(_('$person is already a member'), file=results)
else:
diff --git a/src/mailman/database/schema/mm_20120407000000.py b/src/mailman/database/schema/mm_20120407000000.py
index 068a05834..f6dd60be5 100644
--- a/src/mailman/database/schema/mm_20120407000000.py
+++ b/src/mailman/database/schema/mm_20120407000000.py
@@ -31,6 +31,12 @@ All column changes are in the `mailinglist` table.
- generic_nonmember_action
- nntp_host
+* Added:
+ - list_id
+
+* Changes:
+ member.mailing_list holds the list_id not the fqdn_listname
+
See https://bugs.launchpad.net/mailman/+bug/971013 for details.
"""
@@ -77,29 +83,51 @@ def upgrade_sqlite(database, store, version, module_path):
# rename the temporary table to its place.
database.load_schema(
store, version, 'sqlite_{0}_01.sql'.format(version), module_path)
- results = store.execute(
- 'SELECT id, include_list_post_header, '
- 'news_prefix_subject_too, news_moderation, '
- 'archive, archive_private FROM mailinglist;')
+ results = store.execute("""
+ SELECT id, include_list_post_header,
+ news_prefix_subject_too, news_moderation,
+ archive, archive_private, list_name, mail_host
+ FROM mailinglist;
+ """)
for value in results:
(id, list_post,
news_prefix, news_moderation,
- archive, archive_private) = value
+ archive, archive_private,
+ list_name, mail_host) = value
# Figure out what the new archive_policy column value should be.
- store.execute(
- 'UPDATE ml_backup SET '
- ' allow_list_posts = {0}, '
- ' newsgroup_moderation = {1}, '
- ' nntp_prefix_subject_too = {2}, '
- ' archive_policy = {3} '
- 'WHERE id = {4};'.format(
+ list_id = '{0}.{1}'.format(list_name, mail_host)
+ fqdn_listname = '{0}@{1}'.format(list_name, mail_host)
+ store.execute("""
+ UPDATE ml_backup SET
+ allow_list_posts = {0},
+ newsgroup_moderation = {1},
+ nntp_prefix_subject_too = {2},
+ archive_policy = {3},
+ list_id = '{4}'
+ WHERE id = {5};
+ """.format(
list_post,
news_moderation,
news_prefix,
archive_policy(archive, archive_private),
+ list_id,
id))
+ # Also update the member.mailing_list column to hold the list_id
+ # instead of the fqdn_listname.
+ store.execute("""
+ UPDATE member SET
+ mailing_list = '{0}'
+ WHERE mailing_list = '{1}';
+ """.format(list_id, fqdn_listname))
+ # Pivot the backup table to the real thing.
store.execute('DROP TABLE mailinglist;')
store.execute('ALTER TABLE ml_backup RENAME TO mailinglist;')
+ # Now add some indexes that were previously missing.
+ store.execute(
+ 'CREATE INDEX ix_mailinglist_list_id ON mailinglist (list_id);')
+ store.execute(
+ 'CREATE INDEX ix_mailinglist_fqdn_listname '
+ 'ON mailinglist (list_name, mail_host);')
@@ -108,17 +136,20 @@ def upgrade_postgres(database, store, version, module_path):
results = store.execute(
'SELECT id, archive, archive_private FROM mailinglist;')
# Do the simple renames first.
- store.execute(
- 'ALTER TABLE mailinglist '
- ' RENAME COLUMN news_prefix_subject_too TO nntp_prefix_subject_too;')
- store.execute(
- 'ALTER TABLE mailinglist '
- ' RENAME COLUMN news_moderation TO newsgroup_moderation;')
- store.execute(
- 'ALTER TABLE mailinglist '
- ' RENAME COLUMN include_list_post_header TO allow_list_posts;')
+ store.execute("""
+ ALTER TABLE mailinglist
+ RENAME COLUMN news_prefix_subject_too TO nntp_prefix_subject_too;
+ """)
+ store.execute("""
+ ALTER TABLE mailinglist
+ RENAME COLUMN news_moderation TO newsgroup_moderation;
+ """)
+ store.execute("""
+ ALTER TABLE mailinglist
+ RENAME COLUMN include_list_post_header TO allow_list_posts;
+ """)
# Do the easy column drops next.
- for column in ('archive_volume_frequency',
+ for column in ('archive_volume_frequency',
'generic_nonmember_action',
'nntp_host'):
store.execute(
@@ -130,11 +161,11 @@ def upgrade_postgres(database, store, version, module_path):
# archive_policy from the old values.
for value in results:
id, archive, archive_private = value
- store.execute('UPDATE mailinglist SET '
- ' archive_policy = {0} '
- 'WHERE id = {1};'.format(
- archive_policy(archive, archive_private),
- id))
+ store.execute("""
+ UPDATE mailinglist SET
+ archive_policy = {0}
+ WHERE id = {1};
+ """.format(archive_policy(archive, archive_private), id))
# Now drop the old columns.
for column in ('archive', 'archive_private'):
store.execute(
diff --git a/src/mailman/database/schema/sqlite_20120407000000_01.sql b/src/mailman/database/schema/sqlite_20120407000000_01.sql
index a4eb0adce..c0e752d68 100644
--- a/src/mailman/database/schema/sqlite_20120407000000_01.sql
+++ b/src/mailman/database/schema/sqlite_20120407000000_01.sql
@@ -18,6 +18,7 @@
-- THESE COLUMNS ARE ADDED BY THE PYTHON MIGRATION LAYER:
-- ADD allow_list_posts
-- ADD archive_policy
+-- ADD list_id
-- ADD newsgroup_moderation
-- ADD nntp_prefix_subject_too
@@ -242,5 +243,6 @@ INSERT INTO ml_backup SELECT
-- Add the new columns. They'll get inserted at the Python layer.
ALTER TABLE ml_backup ADD COLUMN archive_policy INTEGER;
+ALTER TABLE ml_backup ADD COLUMN list_id TEXT;
ALTER TABLE ml_backup ADD COLUMN nntp_prefix_subject_too INTEGER;
ALTER TABLE ml_backup ADD COLUMN newsgroup_moderation INTEGER;
diff --git a/src/mailman/database/tests/test_migrations.py b/src/mailman/database/tests/test_migrations.py
index c69a8c545..4ad709c16 100644
--- a/src/mailman/database/tests/test_migrations.py
+++ b/src/mailman/database/tests/test_migrations.py
@@ -54,6 +54,7 @@ class MigrationTestBase(unittest.TestCase):
* news_prefix_subject_too -> nntp_prefix_subject_too
* include_list_post_header -> allow_list_posts
* ADD archive_policy
+ * ADD list_id
* REMOVE archive
* REMOVE archive_private
* REMOVE archive_volume_frequency
@@ -83,6 +84,7 @@ class TestMigration20120407Schema(MigrationTestBase):
# Verify that the database has not yet been migrated.
for missing in ('allow_list_posts',
'archive_policy',
+ 'list_id',
'nntp_prefix_subject_too'):
self.assertRaises(DatabaseError,
self._database.store.execute,
@@ -111,6 +113,7 @@ class TestMigration20120407Schema(MigrationTestBase):
# Verify that the database has been migrated.
for present in ('allow_list_posts',
'archive_policy',
+ 'list_id',
'nntp_prefix_subject_too'):
# This should not produce an exception. Is there some better test
# that we can perform?
@@ -263,6 +266,13 @@ class TestMigration20120407MigratedData(MigrationTestBase):
mlist = getUtility(IListManager).get('test@example.com')
self.assertEqual(mlist.archive_policy, ArchivePolicy.public)
+ def test_list_id(self):
+ # Test that the mailinglist table gets a list_id column.
+ self._upgrade()
+ with temporary_db(self._database):
+ mlist = getUtility(IListManager).get('test@example.com')
+ self.assertEqual(mlist.list_id, 'test.example.com')
+
def test_news_moderation_none(self):
# Test that news_moderation becomes newsgroup_moderation.
self._database.store.execute(
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index f273b099f..94105c65c 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -14,6 +14,18 @@ Here is a history of user visible changes to Mailman.
Architecture
------------
+ * The link between members and the mailing lists they are subscribed to, is
+ now via the RFC 2369 `list_id` instead of the fqdn listname (i.e. posting
+ address). This is because while the posting address can change if the
+ mailing list is moved to a new server, the list id is fixed.
+ (LP: #1024509)
+ + IListManager.get_by_list_id() added.
+ + IListManager.list_ids added.
+ + IMailingList.list_id added.
+ + Several internal APIs that accepted fqdn list names now require list ids,
+ e.g. ISubscriptionService.join() and .find_members().
+ + IMember.list_id attribute added; .mailing_list is now an alias that
+ retrieves and returns the IMailingList.
* `passlib`_ is now used for all password hashing instead of flufl.password.
The default hash is `sha512_crypt`. (LP: #1015758)
* Internally, all datetimes are kept in the UTC timezone, however because of
@@ -66,6 +78,7 @@ Database
- archive and archive_private have been collapsed into archive_policy.
- nntp_host has been removed.
- generic_nonmember_action has been removed (LP: #975696)
+ - list_id added (LP: #1024509)
* The PostgreSQL port of the schema accidentally added a moderation_callback
column to the mailinglist table. Since this is unused in Mailman, it was
simply commented out of the base schema for PostgreSQL.
diff --git a/src/mailman/interfaces/listmanager.py b/src/mailman/interfaces/listmanager.py
index 6f43edf3f..573ba11df 100644
--- a/src/mailman/interfaces/listmanager.py
+++ b/src/mailman/interfaces/listmanager.py
@@ -113,6 +113,15 @@ class IListManager(Interface):
not exist.
"""
+ def get_by_list_id(list_id):
+ """Return the mailing list with the given list id, if it exists.
+
+ :type fqdn_listname: Unicode.
+ :param fqdn_listname: The fully qualified name of the mailing list.
+ :return: the matching `IMailingList` or None if the named list does
+ not exist.
+ """
+
def delete(mlist):
"""Remove the mailing list from the database.
@@ -134,6 +143,10 @@ class IListManager(Interface):
"""An iterator over the fully qualified list names of all mailing
lists managed by this list manager.""")
+ list_ids = Attribute(
+ """An iterator over the list ids of all mailing lists managed by this
+ list manager.""")
+
name_components = Attribute(
"""An iterator over the 2-tuple of (list_name, mail_host) for all
mailing lists managed by this list manager.""")
diff --git a/src/mailman/interfaces/mailinglist.py b/src/mailman/interfaces/mailinglist.py
index c5079bad0..8a4436a21 100644
--- a/src/mailman/interfaces/mailinglist.py
+++ b/src/mailman/interfaces/mailinglist.py
@@ -81,6 +81,11 @@ class IMailingList(Interface):
mail_host is 'example.com'.
""")
+ list_id = Attribute("""\
+ The identity of the mailing list. This value will never change. It
+ is defined in RFC 2369.
+ """)
+
fqdn_listname = Attribute("""\
The read-only fully qualified name of the mailing list. This is the
guaranteed unique id for the mailing list, and it is always the
diff --git a/src/mailman/interfaces/member.py b/src/mailman/interfaces/member.py
index 52bacc72d..997338835 100644
--- a/src/mailman/interfaces/member.py
+++ b/src/mailman/interfaces/member.py
@@ -136,8 +136,11 @@ class IMember(Interface):
member_id = Attribute(
"""The member's unique, random identifier as a UUID.""")
+ list_id = Attribute(
+ """The list id of the mailing list the member is subscribed to.""")
+
mailing_list = Attribute(
- """The mailing list subscribed to.""")
+ """The `IMailingList` that the member is subscribed to.""")
address = Attribute(
"""The email address that's subscribed to the list.""")
diff --git a/src/mailman/interfaces/subscriptions.py b/src/mailman/interfaces/subscriptions.py
index 85f333cf8..cb4900053 100644
--- a/src/mailman/interfaces/subscriptions.py
+++ b/src/mailman/interfaces/subscriptions.py
@@ -69,7 +69,7 @@ class ISubscriptionService(Interface):
:rtype: `IMember`
"""
- def find_members(subscriber=None, fqdn_listname=None, role=None):
+ def find_members(subscriber=None, list_id=None, role=None):
"""Search for and return a specific member.
The members are sorted first by fully-qualified mailing list name,
@@ -80,9 +80,9 @@ class ISubscriptionService(Interface):
:param subscriber: The email address or user id of the user getting
subscribed.
:type subscriber: string or int
- :param fqdn_listname: The posting address of the mailing list to
- search for the subscriber's memberships on.
- :type fqdn_listname: string
+ :param list_id: The list id of the mailing list to search for the
+ subscriber's memberships on.
+ :type list_id: string
:param role: The member role.
:type role: `MemberRole`
:return: The list of all memberships, which may be empty.
@@ -92,8 +92,8 @@ class ISubscriptionService(Interface):
def __iter__():
"""See `get_members()`."""
- def join(fqdn_listname, subscriber, display_name=None,
- delivery_mode=DeliveryMode.regular,
+ def join(list_id, subscriber, display_name=None,
+ delivery_mode=DeliveryMode.regular,
role=MemberRole.member):
"""Subscribe to a mailing list.
@@ -103,9 +103,9 @@ class ISubscriptionService(Interface):
the subscription request is still dependent on the policy of the
mailing list.
- :param fqdn_listname: The posting address of the mailing list to
- subscribe the user to.
- :type fqdn_listname: string
+ :param list_id: The list id of the mailing list the user is
+ subscribing to.
+ :type list_id: string
:param subscriber: The email address or user id of the user getting
subscribed.
:type subscriber: string or int
@@ -130,12 +130,12 @@ class ISubscriptionService(Interface):
:raises ValueError: when `delivery_mode` is invalid.
"""
- def leave(fqdn_listname, email):
+ def leave(list_id, email):
"""Unsubscribe from a mailing list.
- :param fqdn_listname: The posting address of the mailing list to
- unsubscribe the user from.
- :type fqdn_listname: string
+ :param list_id: The list id of the mailing list the user is
+ unsubscribing from.
+ :type list_id: string
:param email: The email address of the user getting unsubscribed.
:type email: string
:raises InvalidEmailAddressError: if the email address is not valid.
diff --git a/src/mailman/model/docs/listmanager.rst b/src/mailman/model/docs/listmanager.rst
index 9c72b18e7..380fe7704 100644
--- a/src/mailman/model/docs/listmanager.rst
+++ b/src/mailman/model/docs/listmanager.rst
@@ -16,28 +16,31 @@ Creating a mailing list
Creating the list returns the newly created IMailList object.
>>> from mailman.interfaces.mailinglist import IMailingList
- >>> mlist = list_manager.create('_xtest@example.com')
+ >>> mlist = list_manager.create('test@example.com')
>>> IMailingList.providedBy(mlist)
True
-All lists with identities have a short name, a host name, and a fully
-qualified listname. This latter is what uniquely distinguishes the mailing
-list to the system.
+All lists with identities have a short name, a host name, a fully qualified
+listname, and an `RFC 2369`_ list id. This latter will not change even if the
+mailing list moves to a different host, so it is what uniquely distinguishes
+the mailing list to the system.
>>> print mlist.list_name
- _xtest
+ test
>>> print mlist.mail_host
example.com
>>> print mlist.fqdn_listname
- _xtest@example.com
+ test@example.com
+ >>> print mlist.list_id
+ test.example.com
If you try to create a mailing list with the same name as an existing list,
you will get an exception.
- >>> list_manager.create('_xtest@example.com')
+ >>> list_manager.create('test@example.com')
Traceback (most recent call last):
...
- ListAlreadyExistsError: _xtest@example.com
+ ListAlreadyExistsError: test@example.com
It is an error to create a mailing list that isn't a fully qualified list name
(i.e. posting address).
@@ -59,9 +62,9 @@ Use the list manager to delete a mailing list.
After deleting the list, you can create it again.
- >>> mlist = list_manager.create('_xtest@example.com')
+ >>> mlist = list_manager.create('test@example.com')
>>> print mlist.fqdn_listname
- _xtest@example.com
+ test@example.com
Retrieving a mailing list
@@ -70,13 +73,21 @@ Retrieving a mailing list
When a mailing list exists, you can ask the list manager for it and you will
always get the same object back.
- >>> mlist_2 = list_manager.get('_xtest@example.com')
+ >>> mlist_2 = list_manager.get('test@example.com')
+ >>> mlist_2 is mlist
+ True
+
+You can also get a mailing list by it's list id.
+
+ >>> mlist_2 = list_manager.get_by_list_id('test.example.com')
>>> mlist_2 is mlist
True
If you try to get a list that doesn't existing yet, you get ``None``.
- >>> print list_manager.get('_xtest_2@example.com')
+ >>> print list_manager.get('test_2@example.com')
+ None
+ >>> print list_manager.get_by_list_id('test_2.example.com')
None
You also get ``None`` if the list name is invalid.
@@ -93,25 +104,34 @@ iterate over the mailing list objects, the list posting addresses, or the list
address components.
::
- >>> mlist_3 = list_manager.create('_xtest_3@example.com')
- >>> mlist_4 = list_manager.create('_xtest_4@example.com')
+ >>> mlist_3 = list_manager.create('test_3@example.com')
+ >>> mlist_4 = list_manager.create('test_4@example.com')
>>> for name in sorted(list_manager.names):
... print name
- _xtest@example.com
- _xtest_3@example.com
- _xtest_4@example.com
+ test@example.com
+ test_3@example.com
+ test_4@example.com
+
+ >>> for list_id in sorted(list_manager.list_ids):
+ ... print list_id
+ test.example.com
+ test_3.example.com
+ test_4.example.com
>>> for fqdn_listname in sorted(m.fqdn_listname
... for m in list_manager.mailing_lists):
... print fqdn_listname
- _xtest@example.com
- _xtest_3@example.com
- _xtest_4@example.com
+ test@example.com
+ test_3@example.com
+ test_4@example.com
>>> for list_name, mail_host in sorted(list_manager.name_components,
... key=lambda (name, host): name):
... print list_name, '@', mail_host
- _xtest @ example.com
- _xtest_3 @ example.com
- _xtest_4 @ example.com
+ test @ example.com
+ test_3 @ example.com
+ test_4 @ example.com
+
+
+.. _`RFC 2369`: http://www.faqs.org/rfcs/rfc2369.html
diff --git a/src/mailman/model/docs/mailinglist.rst b/src/mailman/model/docs/mailinglist.rst
index 895068e52..21c2f0fd8 100644
--- a/src/mailman/model/docs/mailinglist.rst
+++ b/src/mailman/model/docs/mailinglist.rst
@@ -5,11 +5,13 @@ Mailing lists
.. XXX 2010-06-18 BAW: This documentation needs a lot more detail.
The mailing list is a core object in Mailman. It is uniquely identified in
-the system by its posting address, i.e. the email address you would send a
-message to in order to post a message to the mailing list. This must be fully
-qualified.
+the system by its *list-id* which is derived from its posting address,
+i.e. the email address you would send a message to in order to post a message
+to the mailing list. The list id is defined in `RFC 2369`_.
>>> mlist = create_list('aardvark@example.com')
+ >>> print mlist.list_id
+ aardvark.example.com
>>> print mlist.fqdn_listname
aardvark@example.com
@@ -163,3 +165,6 @@ A user cannot subscribe to a mailing list without a preferred address.
...
MissingPreferredAddressError: User must have a preferred address:
<User "Elly Person" (2) at ...>
+
+
+.. _`RFC 2369`: http://www.faqs.org/rfcs/rfc2369.html
diff --git a/src/mailman/model/docs/membership.rst b/src/mailman/model/docs/membership.rst
index f070b4d40..3286bfe6e 100644
--- a/src/mailman/model/docs/membership.rst
+++ b/src/mailman/model/docs/membership.rst
@@ -283,8 +283,8 @@ though that the address their changing to must be verified.
>>> gwen_address = list(gwen.addresses)[0]
>>> gwen_member = bee.subscribe(gwen_address)
>>> for m in bee.members.members:
- ... print m.member_id.int, m.mailing_list, m.address.email
- 7 bee@example.com gwen@example.com
+ ... print m.member_id.int, m.mailing_list.list_id, m.address.email
+ 7 bee.example.com gwen@example.com
Gwen gets a email address.
@@ -301,8 +301,8 @@ address, but the address is not yet verified.
Her membership has not changed.
>>> for m in bee.members.members:
- ... print m.member_id.int, m.mailing_list, m.address.email
- 7 bee@example.com gwen@example.com
+ ... print m.member_id.int, m.mailing_list.list_id, m.address.email
+ 7 bee.example.com gwen@example.com
Gwen verifies her email address, and updates her membership.
@@ -313,5 +313,5 @@ Gwen verifies her email address, and updates her membership.
Now her membership reflects the new address.
>>> for m in bee.members.members:
- ... print m.member_id.int, m.mailing_list, m.address.email
- 7 bee@example.com gperson@example.com
+ ... print m.member_id.int, m.mailing_list.list_id, m.address.email
+ 7 bee.example.com gperson@example.com
diff --git a/src/mailman/model/docs/usermanager.rst b/src/mailman/model/docs/usermanager.rst
index 727f82835..cf7672b27 100644
--- a/src/mailman/model/docs/usermanager.rst
+++ b/src/mailman/model/docs/usermanager.rst
@@ -173,8 +173,9 @@ There are now four members in the system. Sort them by address then role.
... return (member.address.email, member.role.name)
>>> members = sorted(user_manager.members, key=sort_key)
>>> for member in members:
- ... print member.mailing_list, member.address.email, member.role
- test@example.com bperson@example.com MemberRole.member
- test@example.com bperson@example.com MemberRole.owner
- test@example.com eperson@example.com MemberRole.member
- test@example.com fperson@example.com MemberRole.member
+ ... print member.mailing_list.list_id, member.address.email, \
+ ... member.role
+ test.example.com bperson@example.com MemberRole.member
+ test.example.com bperson@example.com MemberRole.owner
+ test.example.com eperson@example.com MemberRole.member
+ test.example.com fperson@example.com MemberRole.member
diff --git a/src/mailman/model/docs/users.rst b/src/mailman/model/docs/users.rst
index 95e08a8d7..997f983b2 100644
--- a/src/mailman/model/docs/users.rst
+++ b/src/mailman/model/docs/users.rst
@@ -335,11 +335,12 @@ membership role.
... return (member.address.email, member.mailing_list,
... int(member.role))
>>> for member in sorted(members, key=sortkey):
- ... print member.address.email, member.mailing_list, member.role
- zperson@example.com xtest_1@example.com MemberRole.member
- zperson@example.net xtest_3@example.com MemberRole.moderator
- zperson@example.org xtest_2@example.com MemberRole.member
- zperson@example.org xtest_2@example.com MemberRole.owner
+ ... print member.address.email, member.mailing_list.list_id, \
+ ... member.role
+ zperson@example.com xtest_1.example.com MemberRole.member
+ zperson@example.net xtest_3.example.com MemberRole.moderator
+ zperson@example.org xtest_2.example.com MemberRole.member
+ zperson@example.org xtest_2.example.com MemberRole.owner
.. _`usermanager.txt`: usermanager.html
diff --git a/src/mailman/model/listmanager.py b/src/mailman/model/listmanager.py
index b4bc4b323..ce94047dd 100644
--- a/src/mailman/model/listmanager.py
+++ b/src/mailman/model/listmanager.py
@@ -48,11 +48,11 @@ class ListManager:
listname, at, hostname = fqdn_listname.partition('@')
if len(hostname) == 0:
raise InvalidEmailAddressError(fqdn_listname)
+ list_id = '{0}.{1}'.format(listname, hostname)
notify(ListCreatingEvent(fqdn_listname))
mlist = store.find(
MailingList,
- MailingList.list_name == listname,
- MailingList.mail_host == hostname).one()
+ MailingList._list_id == list_id).one()
if mlist:
raise ListAlreadyExistsError(fqdn_listname)
mlist = MailingList(fqdn_listname)
@@ -65,9 +65,13 @@ class ListManager:
def get(self, store, fqdn_listname):
"""See `IListManager`."""
listname, at, hostname = fqdn_listname.partition('@')
- return store.find(MailingList,
- list_name=listname,
- mail_host=hostname).one()
+ list_id = '{0}.{1}'.format(listname, hostname)
+ return store.find(MailingList, MailingList._list_id == list_id).one()
+
+ @dbconnection
+ def get_by_list_id(self, store, list_id):
+ """See `IListManager`."""
+ return store.find(MailingList, MailingList._list_id == list_id).one()
@dbconnection
def delete(self, store, mlist):
@@ -101,6 +105,14 @@ class ListManager:
@property
@dbconnection
+ def list_ids(self, store):
+ """See `IListManager`."""
+ result_set = store.find(MailingList)
+ for list_id in result_set.values(MailingList._list_id):
+ yield list_id
+
+ @property
+ @dbconnection
def name_components(self, store):
"""See `IListManager`."""
result_set = store.find(MailingList)
diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py
index 68d086ec5..2c55540be 100644
--- a/src/mailman/model/mailinglist.py
+++ b/src/mailman/model/mailinglist.py
@@ -80,6 +80,7 @@ class MailingList(Model):
# List identity
list_name = Unicode()
mail_host = Unicode()
+ _list_id = Unicode(name='list_id')
allow_list_posts = Bool()
include_rfc2369_headers = Bool()
advertised = Bool()
@@ -199,6 +200,7 @@ class MailingList(Model):
assert hostname, 'Bad list name: {0}'.format(fqdn_listname)
self.list_name = listname
self.mail_host = hostname
+ self._list_id = '{0}.{1}'.format(listname, hostname)
# For the pending database
self.next_request_id = 1
# We need to set up the rosters. Normally, this method will get
@@ -231,6 +233,11 @@ class MailingList(Model):
return '{0}@{1}'.format(self.list_name, self.mail_host)
@property
+ def list_id(self):
+ """See `IMailingList`."""
+ return self._list_id
+
+ @property
def domain(self):
"""See `IMailingList`."""
return getUtility(IDomainManager)[self.mail_host]
@@ -463,7 +470,7 @@ class MailingList(Model):
member = store.find(
Member,
Member.role == role,
- Member.mailing_list == self.fqdn_listname,
+ Member.list_id == self._list_id,
Member._address == subscriber).one()
if member:
raise AlreadySubscribedError(
@@ -474,7 +481,7 @@ class MailingList(Model):
member = store.find(
Member,
Member.role == role,
- Member.mailing_list == self.fqdn_listname,
+ Member.list_id == self._list_id,
Member._user == subscriber).one()
if member:
raise AlreadySubscribedError(
@@ -482,7 +489,7 @@ class MailingList(Model):
else:
raise ValueError('subscriber must be an address or user')
member = Member(role=role,
- mailing_list=self.fqdn_listname,
+ list_id=self._list_id,
subscriber=subscriber)
member.preferences = Preferences()
store.add(member)
diff --git a/src/mailman/model/member.py b/src/mailman/model/member.py
index b791ea0f2..343c69e66 100644
--- a/src/mailman/model/member.py
+++ b/src/mailman/model/member.py
@@ -53,7 +53,7 @@ class Member(Model):
id = Int(primary=True)
_member_id = UUID()
role = Enum(MemberRole)
- mailing_list = Unicode()
+ list_id = Unicode(name='mailing_list')
moderation_action = Enum(Action)
address_id = Int()
@@ -63,10 +63,10 @@ class Member(Model):
user_id = Int()
_user = Reference(user_id, 'User.id')
- def __init__(self, role, mailing_list, subscriber):
+ def __init__(self, role, list_id, subscriber):
self._member_id = uid_factory.new_uid()
self.role = role
- self.mailing_list = mailing_list
+ self.list_id = list_id
if IAddress.providedBy(subscriber):
self._address = subscriber
# Look this up dynamically.
@@ -80,17 +80,23 @@ class Member(Model):
if role in (MemberRole.owner, MemberRole.moderator):
self.moderation_action = Action.accept
elif role is MemberRole.member:
- self.moderation_action = getUtility(IListManager).get(
- mailing_list).default_member_action
+ self.moderation_action = getUtility(IListManager).get_by_list_id(
+ list_id).default_member_action
else:
assert role is MemberRole.nonmember, (
'Invalid MemberRole: {0}'.format(role))
- self.moderation_action = getUtility(IListManager).get(
- mailing_list).default_nonmember_action
+ self.moderation_action = getUtility(IListManager).get_by_list_id(
+ list_id).default_nonmember_action
def __repr__(self):
return '<Member: {0} on {1} as {2}>'.format(
- self.address, self.mailing_list, self.role)
+ self.address, self.mailing_list.fqdn_listname, self.role)
+
+ @property
+ def mailing_list(self):
+ """See `IMember`."""
+ list_manager = getUtility(IListManager)
+ return list_manager.get_by_list_id(self.list_id)
@property
def member_id(self):
diff --git a/src/mailman/model/roster.py b/src/mailman/model/roster.py
index 56dad4bc8..f6f86fbeb 100644
--- a/src/mailman/model/roster.py
+++ b/src/mailman/model/roster.py
@@ -67,8 +67,8 @@ class AbstractRoster:
def _query(self, store):
return store.find(
Member,
- mailing_list=self._mlist.fqdn_listname,
- role=self.role)
+ Member.list_id == self._mlist.list_id,
+ Member.role == self.role)
@property
def members(self):
@@ -106,7 +106,7 @@ class AbstractRoster:
"""See `IRoster`."""
results = store.find(
Member,
- Member.mailing_list == self._mlist.fqdn_listname,
+ Member.list_id == self._mlist.list_id,
Member.role == self.role,
Address.email == address,
Member.address_id == Address.id)
@@ -162,7 +162,7 @@ class AdministratorRoster(AbstractRoster):
def _query(self, store):
return store.find(
Member,
- Member.mailing_list == self._mlist.fqdn_listname,
+ Member.list_id == self._mlist.list_id,
Or(Member.role == MemberRole.owner,
Member.role == MemberRole.moderator))
@@ -171,7 +171,7 @@ class AdministratorRoster(AbstractRoster):
"""See `IRoster`."""
results = store.find(
Member,
- Member.mailing_list == self._mlist.fqdn_listname,
+ Member.list_id == self._mlist.list_id,
Or(Member.role == MemberRole.moderator,
Member.role == MemberRole.owner),
Address.email == address,
@@ -208,7 +208,7 @@ class DeliveryMemberRoster(AbstractRoster):
"""
results = store.find(
Member,
- And(Member.mailing_list == self._mlist.fqdn_listname,
+ And(Member.list_id == self._mlist.list_id,
Member.role == MemberRole.member))
for member in results:
if member.delivery_mode in delivery_modes:
@@ -250,7 +250,7 @@ class Subscribers(AbstractRoster):
@dbconnection
def _query(self, store):
- return store.find(Member, mailing_list=self._mlist.fqdn_listname)
+ return store.find(Member, Member.list_id == self._mlist.list_id)
diff --git a/src/mailman/rest/addresses.py b/src/mailman/rest/addresses.py
index e791dcfbd..2e81cb030 100644
--- a/src/mailman/rest/addresses.py
+++ b/src/mailman/rest/addresses.py
@@ -139,7 +139,7 @@ class UserAddresses(_AddressBase):
def membership_key(member):
# Sort first by mailing list, then by address, then by role.
- return member.mailing_list, member.address.email, int(member.role)
+ return member.list_id, member.address.email, int(member.role)
class AddressMemberships(MemberCollection):
diff --git a/src/mailman/rest/docs/addresses.rst b/src/mailman/rest/docs/addresses.rst
index a8f875d12..cb9242d2b 100644
--- a/src/mailman/rest/docs/addresses.rst
+++ b/src/mailman/rest/docs/addresses.rst
@@ -170,16 +170,16 @@ Elle can get her memberships for each of her email addresses.
entry 0:
address: elle@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/2
entry 1:
address: elle@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: "..."
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -207,16 +207,16 @@ does not show up in the list of memberships for his other address.
entry 0:
address: elle@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/2
entry 1:
address: elle@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: "..."
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -229,8 +229,8 @@ does not show up in the list of memberships for his other address.
entry 0:
address: eperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: "..."
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/2
diff --git a/src/mailman/rest/docs/membership.rst b/src/mailman/rest/docs/membership.rst
index 860d33c21..6189990cb 100644
--- a/src/mailman/rest/docs/membership.rst
+++ b/src/mailman/rest/docs/membership.rst
@@ -43,8 +43,8 @@ the REST interface.
entry 0:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -57,8 +57,8 @@ Bart's specific membership can be accessed directly:
>>> dump_json('http://localhost:9001/3.0/members/1')
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
@@ -71,16 +71,16 @@ the REST interface.
entry 0:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
entry 1:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -98,24 +98,24 @@ subscribes, she is returned first.
entry 0:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
entry 1:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
entry 2:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -137,40 +137,40 @@ User ids are different than member ids.
entry 0:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
entry 1:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
entry 2:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
entry 3:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
entry 4:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -185,16 +185,16 @@ We can also get just the members of a single mailing list.
entry 0:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
entry 1:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
@@ -212,7 +212,7 @@ mailing list.
::
>>> dump_json('http://localhost:9001/3.0/members', {
- ... 'fqdn_listname': 'ant@example.com',
+ ... 'list_id': 'ant.example.com',
... 'subscriber': 'dperson@example.com',
... 'role': 'moderator',
... })
@@ -223,7 +223,7 @@ mailing list.
status: 201
>>> dump_json('http://localhost:9001/3.0/members', {
- ... 'fqdn_listname': 'bee@example.com',
+ ... 'list_id': 'bee.example.com',
... 'subscriber': 'cperson@example.com',
... 'role': 'owner',
... })
@@ -237,56 +237,56 @@ mailing list.
entry 0:
address: dperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: moderator
self_link: http://localhost:9001/3.0/members/6
user: http://localhost:9001/3.0/users/4
entry 1:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
entry 2:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
entry 3:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
entry 4:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
entry 5:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
entry 6:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -301,8 +301,8 @@ We can access all the owners of a list.
entry 0:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -320,8 +320,8 @@ A specific member can always be referenced by their role and address.
... 'bee@example.com/owner/cperson@example.com')
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -335,16 +335,16 @@ example, we can search for all the memberships of a particular address.
entry 0:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/4
user: http://localhost:9001/3.0/users/3
entry 1:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
@@ -355,37 +355,37 @@ example, we can search for all the memberships of a particular address.
Or, we can find all the memberships for a particular mailing list.
>>> dump_json('http://localhost:9001/3.0/members/find', {
- ... 'fqdn_listname': 'bee@example.com',
+ ... 'list_id': 'bee.example.com',
... })
entry 0:
address: aperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/3
user: http://localhost:9001/3.0/users/3
entry 1:
address: bperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/1
user: http://localhost:9001/3.0/users/1
entry 2:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
entry 3:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -398,21 +398,21 @@ list.
>>> dump_json('http://localhost:9001/3.0/members/find', {
... 'subscriber': 'cperson@example.com',
- ... 'fqdn_listname': 'bee@example.com',
+ ... 'list_id': 'bee.example.com',
... })
entry 0:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
entry 1:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: owner
self_link: http://localhost:9001/3.0/members/7
user: http://localhost:9001/3.0/users/2
@@ -429,16 +429,16 @@ Or, we can find all the memberships for an address with a specific role.
entry 0:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/5
user: http://localhost:9001/3.0/users/2
entry 1:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -450,14 +450,14 @@ Finally, we can search for a specific member given all three criteria.
>>> dump_json('http://localhost:9001/3.0/members/find', {
... 'subscriber': 'cperson@example.com',
- ... 'fqdn_listname': 'bee@example.com',
+ ... 'list_id': 'bee.example.com',
... 'role': 'member',
... })
entry 0:
address: cperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: ...
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/2
user: http://localhost:9001/3.0/users/2
@@ -478,7 +478,7 @@ address is not yet known to Mailman, a user is created for her. By default,
get gets a regular delivery.
>>> dump_json('http://localhost:9001/3.0/members', {
- ... 'fqdn_listname': 'ant@example.com',
+ ... 'list_id': 'ant.example.com',
... 'subscriber': 'eperson@example.com',
... 'display_name': 'Elly Person',
... })
@@ -495,8 +495,8 @@ Elly is now a known user, and a member of the mailing list.
>>> elly
<User "Elly Person" (...) at ...>
- >>> set(member.mailing_list for member in elly.memberships.members)
- set([u'ant@example.com'])
+ >>> set(member.list_id for member in elly.memberships.members)
+ set([u'ant.example.com'])
>>> dump_json('http://localhost:9001/3.0/members')
entry 0:
@@ -504,8 +504,8 @@ Elly is now a known user, and a member of the mailing list.
entry 3:
address: eperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: ...
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/8
user: http://localhost:9001/3.0/users/5
@@ -530,7 +530,7 @@ list with her preferred address.
>>> transaction.commit()
>>> dump_json('http://localhost:9001/3.0/members', {
- ... 'fqdn_listname': 'ant@example.com',
+ ... 'list_id': 'ant.example.com',
... 'subscriber': user_id,
... })
content-length: 0
@@ -545,8 +545,8 @@ list with her preferred address.
entry 4:
address: gwen@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/9
user: http://localhost:9001/3.0/users/6
@@ -568,8 +568,8 @@ the new address.
entry 4:
address: gwen.person@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/9
user: http://localhost:9001/3.0/users/6
@@ -606,7 +606,7 @@ Fred joins the `ant` mailing list but wants MIME digest delivery.
>>> transaction.abort()
>>> dump_json('http://localhost:9001/3.0/members', {
- ... 'fqdn_listname': 'ant@example.com',
+ ... 'list_id': 'ant.example.com',
... 'subscriber': 'fperson@example.com',
... 'display_name': 'Fred Person',
... 'delivery_mode': 'mime_digests',
@@ -633,8 +633,8 @@ Fred is getting MIME deliveries.
>>> dump_json('http://localhost:9001/3.0/members/10')
address: fperson@example.com
delivery_mode: mime_digests
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/10
user: http://localhost:9001/3.0/users/7
@@ -655,8 +655,8 @@ This can be done by PATCH'ing his member with the `delivery_mode` parameter.
>>> dump_json('http://localhost:9001/3.0/members/10')
address: fperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/10
user: http://localhost:9001/3.0/users/7
@@ -673,8 +673,8 @@ If a PATCH request changes no attributes, nothing happens.
>>> dump_json('http://localhost:9001/3.0/members/10')
address: fperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/10
user: http://localhost:9001/3.0/users/7
@@ -715,8 +715,8 @@ addresses.
entry 5:
address: herb@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/11
user: http://localhost:9001/3.0/users/8
@@ -724,8 +724,8 @@ addresses.
entry 10:
address: herb@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: "..."
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/12
user: http://localhost:9001/3.0/users/8
@@ -780,16 +780,16 @@ his membership ids have not changed.
entry 0:
address: hperson@example.com
delivery_mode: regular
- fqdn_listname: ant@example.com
http_etag: "..."
+ list_id: ant.example.com
role: member
self_link: http://localhost:9001/3.0/members/11
user: http://localhost:9001/3.0/users/8
entry 1:
address: hperson@example.com
delivery_mode: regular
- fqdn_listname: bee@example.com
http_etag: "..."
+ list_id: bee.example.com
role: member
self_link: http://localhost:9001/3.0/members/12
user: http://localhost:9001/3.0/users/8
diff --git a/src/mailman/rest/lists.py b/src/mailman/rest/lists.py
index 3374e8f73..f25133211 100644
--- a/src/mailman/rest/lists.py
+++ b/src/mailman/rest/lists.py
@@ -137,7 +137,7 @@ class AList(_ListBase):
"""Delete the named mailing list."""
if self._mlist is None:
return http.not_found()
- remove_list(self._mlist.fqdn_listname, self._mlist)
+ remove_list(self._mlist)
return no_content()
@resource.child(member_matcher)
@@ -146,7 +146,7 @@ class AList(_ListBase):
if self._mlist is None:
return http.not_found()
members = getUtility(ISubscriptionService).find_members(
- email, self._mlist.fqdn_listname, role)
+ email, self._mlist.list_id, role)
if len(members) == 0:
return http.not_found()
assert len(members) == 1, 'Too many matches'
diff --git a/src/mailman/rest/members.py b/src/mailman/rest/members.py
index 761e3147c..c6aaa7e39 100644
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -61,7 +61,7 @@ class _MemberBase(resource.Resource, CollectionMixin):
user_id = member.user.user_id.int
member_id = member.member_id.int
return dict(
- fqdn_listname=member.mailing_list,
+ list_id=member.list_id,
address=member.address.email,
role=role,
user=path_to('users/{0}'.format(user_id)),
@@ -148,7 +148,7 @@ class AMember(_MemberBase):
# an admin or user notification.
if self._member is None:
return http.not_found()
- mlist = getUtility(IListManager).get(self._member.mailing_list)
+ mlist = getUtility(IListManager).get_by_list_id(self._member.list_id)
if self._member.role is MemberRole.member:
try:
delete_member(mlist, self._member.address.email, False, False)
@@ -197,7 +197,7 @@ class AllMembers(_MemberBase):
service = getUtility(ISubscriptionService)
try:
validator = Validator(
- fqdn_listname=unicode,
+ list_id=unicode,
subscriber=subscriber_validator,
display_name=unicode,
delivery_mode=enum_validator(DeliveryMode),
@@ -248,10 +248,10 @@ class FindMembers(_MemberBase):
"""Find a member"""
service = getUtility(ISubscriptionService)
validator = Validator(
- fqdn_listname=unicode,
+ list_id=unicode,
subscriber=unicode,
role=enum_validator(MemberRole),
- _optional=('fqdn_listname', 'subscriber', 'role'))
+ _optional=('list_id', 'subscriber', 'role'))
members = service.find_members(**validator(request))
# We can't just return the _FoundMembers instance, because
# CollectionMixins have only a GET method, which is incompatible with
diff --git a/src/mailman/rest/tests/test_membership.py b/src/mailman/rest/tests/test_membership.py
index 875f5e254..18469e537 100644
--- a/src/mailman/rest/tests/test_membership.py
+++ b/src/mailman/rest/tests/test_membership.py
@@ -53,7 +53,7 @@ class TestMembership(unittest.TestCase):
try:
# For Python 2.6.
call_api('http://localhost:9001/3.0/members', {
- 'fqdn_listname': 'missing@example.com',
+ 'list_id': 'missing.example.com',
'subscriber': 'nobody@example.com',
})
except HTTPError as exc:
@@ -112,7 +112,7 @@ class TestMembership(unittest.TestCase):
try:
# For Python 2.6.
call_api('http://localhost:9001/3.0/members', {
- 'fqdn_listname': 'test@example.com',
+ 'list_id': 'test.example.com',
'subscriber': 'anne@example.com',
})
except HTTPError as exc:
@@ -124,7 +124,7 @@ class TestMembership(unittest.TestCase):
def test_join_with_invalid_delivery_mode(self):
try:
call_api('http://localhost:9001/3.0/members', {
- 'fqdn_listname': 'test@example.com',
+ 'list_id': 'test.example.com',
'subscriber': 'anne@example.com',
'display_name': 'Anne Person',
'delivery_mode': 'invalid-mode',
@@ -138,7 +138,7 @@ class TestMembership(unittest.TestCase):
def test_join_email_contains_slash(self):
content, response = call_api('http://localhost:9001/3.0/members', {
- 'fqdn_listname': 'test@example.com',
+ 'list_id': 'test.example.com',
'subscriber': 'hugh/person@example.com',
'display_name': 'Hugh Person',
})
@@ -168,7 +168,7 @@ class TestMembership(unittest.TestCase):
self.assertEqual(entry_0['role'], 'member')
self.assertEqual(entry_0['user'], 'http://localhost:9001/3.0/users/1')
self.assertEqual(entry_0['address'], 'anne@example.com')
- self.assertEqual(entry_0['fqdn_listname'], 'test@example.com')
+ self.assertEqual(entry_0['list_id'], 'test.example.com')
def test_member_changes_preferred_address(self):
with transaction():
diff --git a/src/mailman/styles/default.py b/src/mailman/styles/default.py
index 86863726c..cb4da396d 100644
--- a/src/mailman/styles/default.py
+++ b/src/mailman/styles/default.py
@@ -55,7 +55,6 @@ class DefaultStyle:
mlist = mailing_list
# List identity.
mlist.display_name = mlist.list_name.capitalize()
- mlist.list_id = '{0.list_name}.{0.mail_host}'.format(mlist)
mlist.include_rfc2369_headers = True
mlist.allow_list_posts = True
# Most of these were ripped from the old MailList.InitVars() method.
diff --git a/src/mailman/utilities/tests/test_import.py b/src/mailman/utilities/tests/test_import.py
index 2cc0dafe5..396da4aa8 100644
--- a/src/mailman/utilities/tests/test_import.py
+++ b/src/mailman/utilities/tests/test_import.py
@@ -45,7 +45,7 @@ class TestBasicImport(unittest.TestCase):
self._pckdict = cPickle.load(fp)
def tearDown(self):
- remove_list(self._mlist.fqdn_listname, self._mlist)
+ remove_list(self._mlist)
def _import(self):
import_config_pck(self._mlist, self._pckdict)