summaryrefslogtreecommitdiff
path: root/Mailman/docs
diff options
context:
space:
mode:
authorBarry Warsaw2007-06-09 15:20:32 -0400
committerBarry Warsaw2007-06-09 15:20:32 -0400
commit3231fd628f6eea30bd6e2be56eb419ed0008d954 (patch)
tree176f80a7b4f72c410e30ab9ba3e3fe2deb1bb1fe /Mailman/docs
parente5c04e2a93a58d799dd3940a7935853eb1f2e3e4 (diff)
downloadmailman-3231fd628f6eea30bd6e2be56eb419ed0008d954.tar.gz
mailman-3231fd628f6eea30bd6e2be56eb419ed0008d954.tar.zst
mailman-3231fd628f6eea30bd6e2be56eb419ed0008d954.zip
Implement the new, simplified membership model. Rosters and RosterSets as
they were previously known are now gone. Rosters, rather than being a database entity that collects users, is now just a filter on the member database. This way, we can use generic rosters to search for regular members, digest members, owners, or moderators. More advanced rosters can do all kinds of other membership queries. But rosters no longer need to be a database entity. Users have a name, password, optional preferences, and a set of addresses, but users are not subscribed to mailing lists. Addresses have the email address, some verification information, and optional preferences. Members tie an address to a mailing list, through a role, with optional preferences. Other changes here include: MailList.fqdn_listname() moved to the MailingList model entity. Added MemberRole enum and SystemDefaultPreferences to Mailman.constants. Profiles are renamed to Preferences (same with the interface), but the files are not yet moved. This happens later. We mostly don't need has_*() relationships on the entity classes, because we generally don't need the reverse relationship. Use belongs_to() because that creates the foreign key, even though the wording seems counter intuitive. IAddress.subscribe() added. Tell Elixir to use shortnames for all tables. Remove the OldStyleMembership fields from MailingList. Remove all the interface elements and database fields that talk about rosters and rostersets. Convert Version entity to has_field().
Diffstat (limited to 'Mailman/docs')
-rw-r--r--Mailman/docs/membership.txt183
1 files changed, 183 insertions, 0 deletions
diff --git a/Mailman/docs/membership.txt b/Mailman/docs/membership.txt
new file mode 100644
index 000000000..36b1508a8
--- /dev/null
+++ b/Mailman/docs/membership.txt
@@ -0,0 +1,183 @@
+List memberships
+================
+
+Users represent people in Mailman. Users control email addresses, and rosters
+are collectons of members. A member gives an email address a role, such as
+'member', 'administrator', or 'moderator'. Roster sets are collections of
+rosters and a mailing list has a single roster set that contains all its
+members, regardless of that member's role.
+
+Mailing lists and roster sets have an indirect relationship, through the
+roster set's name. Roster also have names, but are related to roster sets
+by a more direct containment relationship. This is because it is possible to
+store mailing list data in a different database than user data.
+
+When we create a mailing list, it starts out with no members...
+
+ >>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
+ >>> mlist = config.list_manager.create('_xtest@example.com')
+ >>> flush()
+ >>> mlist
+ <mailing list "_xtest@example.com" (unlocked) at ...>
+ >>> sorted(member.address.address for member in mlist.members.members)
+ []
+ >>> sorted(user.real_name for user in mlist.members.users)
+ []
+ >>> sorted(address.address for member in mlist.members.addresses)
+ []
+
+...no owners...
+
+ >>> sorted(member.address.address for member in mlist.owners.members)
+ []
+ >>> sorted(user.real_name for user in mlist.owners.users)
+ []
+ >>> sorted(address.address for member in mlist.owners.addresses)
+ []
+
+...no moderators...
+
+ >>> sorted(member.address.address for member in mlist.moderators.members)
+ []
+ >>> sorted(user.real_name for user in mlist.moderators.users)
+ []
+ >>> sorted(address.address for member in mlist.moderators.addresses)
+ []
+
+...and no administrators.
+
+ >>> sorted(member.address.address
+ ... for member in mlist.administrators.members)
+ []
+ >>> sorted(user.real_name for user in mlist.administrators.users)
+ []
+ >>> sorted(address.address for member in mlist.administrators.addresses)
+ []
+
+
+
+Administrators
+--------------
+
+A mailing list's administrators are defined as union of the list's owners and
+the list's moderators. We can add new owners or moderators to this list by
+assigning roles to users. First we have to create the user, because there are
+no users in the user database yet.
+
+ >>> user_1 = config.user_manager.create_user(
+ ... 'aperson@example.com', 'Anne Person')
+ >>> flush()
+ >>> user_1.real_name
+ 'Anne Person'
+ >>> sorted(address.address for address in user_1.addresses)
+ ['aperson@example.com']
+
+We can add Anne as an owner of the mailing list, by creating a member role for
+her.
+
+ >>> from Mailman.constants import MemberRole
+ >>> address_1 = list(user_1.addresses)[0]
+ >>> address_1.address
+ 'aperson@example.com'
+ >>> address_1.subscribe(mlist, MemberRole.owner)
+ <Member: Anne Person <aperson@example.com> on
+ _xtest@example.com as MemberRole.owner>
+ >>> flush()
+ >>> sorted(member.address.address for member in mlist.owners.members)
+ ['aperson@example.com']
+ >>> sorted(user.real_name for user in mlist.owners.users)
+ ['Anne Person']
+ >>> sorted(address.address for address in mlist.owners.addresses)
+ ['aperson@example.com']
+
+Adding Anne as a list owner also makes her an administrator, but does not make
+her a moderator. Nor does it make her a member of the list.
+
+ >>> sorted(user.real_name for user in mlist.administrators.users)
+ ['Anne Person']
+ >>> sorted(user.real_name for user in mlist.moderators.users)
+ []
+ >>> sorted(user.real_name for user in mlist.members.users)
+ []
+
+We can add Ben as a moderator of the list, by creating a different member role
+for him.
+
+ >>> user_2 = config.user_manager.create_user(
+ ... 'bperson@example.com', 'Ben Person')
+ >>> flush()
+ >>> user_2.real_name
+ 'Ben Person'
+ >>> address_2 = list(user_2.addresses)[0]
+ >>> address_2.address
+ 'bperson@example.com'
+ >>> address_2.subscribe(mlist, MemberRole.moderator)
+ <Member: Ben Person <bperson@example.com>
+ on _xtest@example.com as MemberRole.moderator>
+ >>> flush()
+ >>> sorted(member.address.address for member in mlist.moderators.members)
+ ['bperson@example.com']
+ >>> sorted(user.real_name for user in mlist.moderators.users)
+ ['Ben Person']
+ >>> sorted(address.address for address in mlist.moderators.addresses)
+ ['bperson@example.com']
+
+Now, both Anne and Ben are list administrators.
+
+ >>> sorted(member.address.address
+ ... for member in mlist.administrators.members)
+ ['aperson@example.com', 'bperson@example.com']
+ >>> sorted(user.real_name for user in mlist.administrators.users)
+ ['Anne Person', 'Ben Person']
+ >>> sorted(address.address for address in mlist.administrators.addresses)
+ ['aperson@example.com', 'bperson@example.com']
+
+
+Members
+-------
+
+Similarly, list members are born of users being given the proper role. It's
+more interesting here because these roles should have a preference which can
+be used to decide whether the member is to get regular delivery or digest
+delivery. Without a preference, Mailman will fall back first to the address's
+preference, then the user's preference, then the list's preference. Start
+without any member preference to see the system defaults.
+
+ >>> user_3 = config.user_manager.create_user(
+ ... 'cperson@example.com', 'Claire Person')
+ >>> flush()
+ >>> user_3.real_name
+ 'Claire Person'
+ >>> address_3 = list(user_3.addresses)[0]
+ >>> address_3.address
+ 'cperson@example.com'
+ >>> address_3.subscribe(mlist, MemberRole.member)
+ <Member: Claire Person <cperson@example.com>
+ on _xtest@example.com as MemberRole.member>
+ >>> flush()
+
+Claire will be a regular delivery member but not a digest member.
+
+ >>> sorted(address.address for address in mlist.members.addresses)
+ ['cperson@example.com']
+ >>> sorted(address.address for address in mlist.regular_members.addresses)
+ ['cperson@example.com']
+ >>> sorted(address.address for address in mlist.digest_members.addresses)
+ []
+
+It's easy to make the list administrators members of the mailing list too.
+
+ >>> for address in mlist.administrators.addresses:
+ ... address.subscribe(mlist, MemberRole.member)
+ <Member: Ben Person <bperson@example.com> on
+ _xtest@example.com as MemberRole.member>
+ <Member: Anne Person <aperson@example.com> on
+ _xtest@example.com as MemberRole.member>
+ >>> flush()
+ >>> sorted(address.address for address in mlist.members.addresses)
+ ['aperson@example.com', 'bperson@example.com', 'cperson@example.com']
+ >>> sorted(address.address for address in mlist.regular_members.addresses)
+ ['aperson@example.com', 'bperson@example.com', 'cperson@example.com']
+ >>> sorted(address.address for address in mlist.digest_members.addresses)
+ []