diff options
| author | Barry Warsaw | 2007-12-30 02:47:45 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2007-12-30 02:47:45 -0500 |
| commit | 5b4bb22feca4d520afef44d1c472807e020d17b5 (patch) | |
| tree | 8d85431b8d129fad6c29dabd4d03c2eabe8a11d7 | |
| parent | 66ffab7c0d56b8144a80045fac3a7dab036a597f (diff) | |
| download | mailman-5b4bb22feca4d520afef44d1c472807e020d17b5.tar.gz mailman-5b4bb22feca4d520afef44d1c472807e020d17b5.tar.zst mailman-5b4bb22feca4d520afef44d1c472807e020d17b5.zip | |
| -rw-r--r-- | Mailman/Message.py | 5 | ||||
| -rw-r--r-- | Mailman/database/mailman.sql | 1 | ||||
| -rw-r--r-- | Mailman/database/member.py | 2 | ||||
| -rw-r--r-- | Mailman/docs/moderation.txt | 71 | ||||
| -rw-r--r-- | Mailman/docs/no-subject.txt | 35 | ||||
| -rw-r--r-- | Mailman/interfaces/member.py | 3 | ||||
| -rw-r--r-- | Mailman/rules/moderation.py | 69 | ||||
| -rw-r--r-- | Mailman/rules/no_subject.py | 45 |
8 files changed, 230 insertions, 1 deletions
diff --git a/Mailman/Message.py b/Mailman/Message.py index 89bc42798..a9256dc90 100644 --- a/Mailman/Message.py +++ b/Mailman/Message.py @@ -58,7 +58,10 @@ class Message(email.message.Message): return value def get_all(self, name, failobj=None): - all_values = email.message.Message.get_all(self, name, failobj) + missing = object() + all_values = email.message.Message.get_all(self, name, missing) + if all_values is missing: + return failobj return [(unicode(value, 'ascii') if isinstance(value, str) else value) for value in all_values] diff --git a/Mailman/database/mailman.sql b/Mailman/database/mailman.sql index cff4daba0..c511e6180 100644 --- a/Mailman/database/mailman.sql +++ b/Mailman/database/mailman.sql @@ -145,6 +145,7 @@ CREATE TABLE member ( id INTEGER NOT NULL, role TEXT, mailing_list TEXT, + is_moderated BOOLEAN, address_id INTEGER, preferences_id INTEGER, PRIMARY KEY (id), diff --git a/Mailman/database/member.py b/Mailman/database/member.py index f77b8c7c3..b24688423 100644 --- a/Mailman/database/member.py +++ b/Mailman/database/member.py @@ -33,6 +33,7 @@ class Member(Model): id = Int(primary=True) role = Enum() mailing_list = Unicode() + is_moderated = Bool() address_id = Int() address = Reference(address_id, 'Address.id') @@ -43,6 +44,7 @@ class Member(Model): self.role = role self.mailing_list = mailing_list self.address = address + self.is_moderated = False def __repr__(self): return '<Member: %s on %s as %s>' % ( diff --git a/Mailman/docs/moderation.txt b/Mailman/docs/moderation.txt new file mode 100644 index 000000000..0ce6bee6e --- /dev/null +++ b/Mailman/docs/moderation.txt @@ -0,0 +1,71 @@ +Member moderation +================= + +Each user has a moderation flag. When set, and the list is set to moderate +postings, then only members with a cleared moderation flag will be able to +email the list without having those messages be held for approval. The +'moderation' rule determines whether the message should be moderated or not. + + >>> from Mailman.configuration import config + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> from Mailman.app.rules import find_rule + >>> rule = find_rule('moderation') + >>> rule.name + 'moderation' + +In the simplest case, the sender is not a member of the mailing list, so the +moderation rule can't match. + + >>> msg = message_from_string(u"""\ + ... From: aperson@example.org + ... To: _xtest@example.com + ... Subject: A posted message + ... + ... """) + >>> rule.check(mlist, msg, {}) + False + +Let's add the message author as a non-moderated member. + + >>> user = config.db.user_manager.create_user( + ... u'aperson@example.org', u'Anne Person') + >>> address = list(user.addresses)[0] + >>> from Mailman.interfaces import MemberRole + >>> member = address.subscribe(mlist, MemberRole.member) + >>> member.is_moderated + False + >>> rule.check(mlist, msg, {}) + False + +Once the member's moderation flag is set though, the rule matches. + + >>> member.is_moderated = True + >>> rule.check(mlist, msg, {}) + True + + +Non-members +----------- + +There is another, related rule for matching non-members, which simply matches +if the sender is /not/ a member of the mailing list. + + >>> rule = find_rule('non-member') + >>> rule.name + 'non-member' + +If the sender is a member of this mailing list, the rule does not match. + + >>> rule.check(mlist, msg, {}) + False + +But if the sender is not a member of this mailing list, the rule matches. + + >>> msg = message_from_string(u"""\ + ... From: bperson@example.org + ... To: _xtest@example.com + ... Subject: A posted message + ... + ... """) + >>> rule.check(mlist, msg, {}) + True diff --git a/Mailman/docs/no-subject.txt b/Mailman/docs/no-subject.txt new file mode 100644 index 000000000..3c6dc88bf --- /dev/null +++ b/Mailman/docs/no-subject.txt @@ -0,0 +1,35 @@ +No Subject header +================= + +This rule matches if the message has no Subject header, or if the header is +the empty string when stripped. + + >>> from Mailman.configuration import config + >>> mlist = config.db.list_manager.create(u'_xtest@example.com') + >>> from Mailman.app.rules import find_rule + >>> rule = find_rule('no-subject') + >>> rule.name + 'no-subject' + +A message with a non-empty subject does not match the rule. + + >>> msg = message_from_string(u"""\ + ... From: aperson@example.org + ... To: _xtest@example.com + ... Subject: A posted message + ... + ... """) + >>> rule.check(mlist, msg, {}) + False + +Delete the Subject header and the rule matches. + + >>> del msg['subject'] + >>> rule.check(mlist, msg, {}) + True + +Even a Subject header with only whitespace still matches the rule. + + >>> msg['Subject'] = u' ' + >>> rule.check(mlist, msg, {}) + True diff --git a/Mailman/interfaces/member.py b/Mailman/interfaces/member.py index 18f0b034e..8fc410a77 100644 --- a/Mailman/interfaces/member.py +++ b/Mailman/interfaces/member.py @@ -78,6 +78,9 @@ class IMember(Interface): role = Attribute( """The role of this membership.""") + is_moderated = Attribute( + """True if the membership is moderated, otherwise False.""") + def unsubscribe(): """Unsubscribe (and delete) this member from the mailing list.""" diff --git a/Mailman/rules/moderation.py b/Mailman/rules/moderation.py new file mode 100644 index 000000000..5b0820426 --- /dev/null +++ b/Mailman/rules/moderation.py @@ -0,0 +1,69 @@ +# Copyright (C) 2007 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +"""Membership related rules.""" + +__all__ = [ + 'moderation_rule', + 'nonmember_rule', + ] +__metaclass__ = type + + +from zope.interface import implements + +from Mailman.i18n import _ +from Mailman.interfaces import IRule + + + +class Moderation: + """The member moderation rule.""" + implements(IRule) + + name = 'moderation' + description = _('Match messages sent by moderated members.') + + def check(self, mlist, msg, msgdata): + """See `IRule`.""" + for sender in msg.get_senders(): + member = mlist.members.get_member(sender) + if member is not None and member.is_moderated: + return True + return False + + + +class NonMember: + """The non-membership rule.""" + implements(IRule) + + name = 'non-member' + description = _('Match messages sent by non-members.') + + def check(self, mlist, msg, msgdata): + """See `IRule`.""" + for sender in msg.get_senders(): + if mlist.members.get_member(sender) is not None: + # The sender is a member of the mailing list. + return False + return True + + + +moderation_rule = Moderation() +nonmember_rule = NonMember() diff --git a/Mailman/rules/no_subject.py b/Mailman/rules/no_subject.py new file mode 100644 index 000000000..ca7cbd9d2 --- /dev/null +++ b/Mailman/rules/no_subject.py @@ -0,0 +1,45 @@ +# Copyright (C) 2007 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +"""The no-Subject header rule.""" + +__all__ = ['no_subject_rule'] +__metaclass__ = type + + +from zope.interface import implements + +from Mailman.i18n import _ +from Mailman.interfaces import IRule + + + +class NoSubject: + """The no-Subject rule.""" + implements(IRule) + + name = 'no-subject' + description = _('Catch messages with no, or empty, Subject headers.') + + def check(self, mlist, msg, msgdata): + """See `IRule`.""" + subject = msg.get('subject', '').strip() + return subject == '' + + + +no_subject_rule = NoSubject() |
