Coverage for src/postorius/forms/list_forms.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- # Copyright (C) 2017-2019 by the Free Software Foundation, Inc. # # This file is part of Postorius. # # Postorius is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # Postorius 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 # Postorius. If not, see <http://www.gnu.org/licenses/>. #
("hold", _("Hold for moderation")), ("reject", _("Reject (with notification)")), ("discard", _("Discard (no notification)")), ("accept", _("Accept immediately (bypass other rules)")), ("defer", _("Default processing")), )
""" Form fields to add a new list. Languages are hard coded which should be replaced by a REST lookup of available languages. """ label=_('List Name'), required=True, error_messages={'required': _('Please enter a name for your list.'), 'invalid': _('Please enter a valid list name.')}) label=_('Initial list owner address'), error_messages={ 'required': _("Please enter the list owner's email address.")}, required=True) widget=forms.RadioSelect(), label=_('Advertise this list?'), error_messages={ 'required': _("Please choose a list type.")}, required=True, choices=( (True, _("Advertise this list in list index")), (False, _("Hide this list in list index")))) label=_('Description'), required=False)
widget=forms.Select(), label=_('Mail Host'), required=True, choices=domain_choices, error_messages={'required': _("Choose an existing Domain."), 'invalid': _("Choose a valid Mail Host")}) widget=forms.Select(), label=_('List Style'), required=True, choices=style_choices, error_messages={'required': _("Choose a List Style."), 'invalid': _("Choose a valid List Style.")}) "Site admin has not created any domains") # if len(choices) < 2: # help_text=_("No domains available: " + # "The site admin must create new domains " + # "before you will be able to create a list")
# TODO (maxking): Error should atleast point to what is a valid # listname. It may not always be obvious which characters aren't # allowed in a listname.
""" Class to handle the automatic insertion of fieldsets and divs.
To use it: add a list for each wished fieldset. The first item in the list should be the wished name of the fieldset, the following the fields that should be included in the fieldset. """ "listname", "mail_host", "list_style", "list_owner", "description", "advertised"], ]
"""Form fields to join an existing list. """
label=_('Your email address'), validators=[validate_email], widget=forms.Select(), error_messages={ 'required': _('Please enter an email address.'), 'invalid': _('Please enter a valid email address.')})
label=_('Your name (optional)'), required=False)
for address in user_emails)
"""Form fields to join an existing list as an anonymous user. """
label=_('Your email address'), validators=[validate_email], error_messages={ 'required': _('Please enter an email address.'), 'invalid': _('Please enter a valid email address.')})
label=_('Your name (optional)'), required=False)
""" Base class for list settings forms. """
('open', _('Open')), ('confirm', _('Confirm')), ('moderate', _('Moderate')), ('confirm_then_moderate', _('Confirm, then moderate')), )
""" List subscription policy settings. """ label=_('Subscription Policy'), choices=SUBSCRIPTION_POLICY_CHOICES, help_text=_('Open: Subscriptions are added automatically\n' 'Confirm: Subscribers need to confirm the subscription ' 'using an email sent to them\n' 'Moderate: Moderators will have to authorize ' 'each subscription manually.\n' 'Confirm then Moderate: First subscribers have to confirm,' ' then a moderator needs to authorize.'))
""" Set the general archive policy. """
("public", _("Public archives")), ("private", _("Private archives")), ("never", _("Do not archive this list")), )
choices=archive_policy_choices, widget=forms.RadioSelect, label=_('Archive policy'), help_text=_('Policy for archiving messages for this list'), )
widget=forms.CheckboxSelectMultiple, label=_('Active archivers'), required=False) # May be empty if no archivers are desired.
[(key, key) for key in archiver_opts]) key for key in archiver_opts if self._mlist.archivers[key] is True] # noqa
""" List messages acceptance settings. """ label=_("Acceptable aliases"), required=False, help_text=_( 'This is a list, one per line, of addresses and regexps matching ' 'addresses that are acceptable in To: or Cc: in lieu of the list ' 'posting address when `require_explicit_destination\' is enabled. ' ' Entries are either email addresses or regexps matching email ' 'addresses. Regexps are entries beginning with `^\' and are ' 'matched against every recipient address in the message. The ' 'matching is performed with Python\'s re.match() function, meaning' ' they are anchored to the start of the string.')) widget=forms.RadioSelect(choices=((True, _('Yes')), (False, _('No')))), required=False, label=_('Require Explicit Destination'), help_text=_( 'This checks to ensure that the list posting address or an ' 'acceptable alias explicitly appears in a To: or Cc: header in ' 'the post.')) widget=forms.RadioSelect(choices=((True, _('Yes')), (False, _('No')))), required=False, label=_('Administrivia'), help_text=_( 'Administrivia tests will check postings to see whether it\'s ' 'really meant as an administrative request (like subscribe, ' 'unsubscribe, etc), and will add it to the the administrative ' 'requests queue, notifying the administrator of the new request, ' 'in the process.')) widget=forms.RadioSelect(), label=_('Default action to take when a member posts to the list'), error_messages={ 'required': _("Please choose a default member action.")}, required=True, choices=ACTION_CHOICES, help_text=_( 'Default action to take when a member posts to the list.\n' 'Hold: This holds the message for approval by the list ' 'moderators.\n' 'Reject: this automatically rejects the message by sending a ' 'bounce notice to the post\'s author. The text of the bounce ' 'notice can be configured by you.\n' 'Discard: this simply discards the message, with no notice ' 'sent to the post\'s author.\n' 'Accept: accepts any postings without any further checks.\n' 'Default Processing: run additional checks and accept ' 'the message.')) widget=forms.RadioSelect(), label=_('Default action to take when a non-member posts to the list'), error_messages={ 'required': _("Please choose a default non-member action.")}, required=True, choices=ACTION_CHOICES, help_text=_( 'When a post from a non-member is received, the message\'s sender ' 'is matched against the list of explicitly accepted, held, ' 'rejected (bounced), and discarded addresses. ' 'If no match is found, then this action is taken.')) min_value=0, label=_('Maximum message size'), required=False, help_text=_( 'The maximum allowed message size. ' 'This can be used to prevent emails with large attachments. ' 'A size of 0 disables the check.')) min_value=0, label=_('Maximum number of recipients'), required=False, help_text=_( 'The maximum number of recipients for a message. ' 'This can be used to prevent mass mailings from being accepted. ' 'A value of 0 disables the check.'))
# python's urlencode will drop this attribute completely if an empty # list is passed with doseq=True. To make it work for us, we instead # use an empty string to signify an empty value. In turn, Core will # also consider an empty value to be empty list for list-of-strings # field. try: re.compile(alias) except re.error as e: raise forms.ValidationError( _('Invalid alias regexp: {}: {}').format(alias, e.msg)) else: except ValidationError: raise forms.ValidationError( _('Invalid alias email: {}').format(alias))
""" List digest settings. """ label=_('Digest size threshold'), help_text=_('How big in Kb should a digest be before ' 'it gets sent out?'))
""" DMARC Mitigations list settings. """ label=_('DMARC mitigation action'), widget=forms.Select(), required=False, error_messages={ 'required': _("Please choose a DMARC mitigation action.")}, choices=( ('no_mitigation', _('No DMARC mitigations')), ('munge_from', _('Replace From: with list address')), ('wrap_message', _('Wrap the message in an outer message From: the list.')), ('reject', _('Reject the message')), ('discard', _('Discard the message'))), help_text=_( 'The action to apply to messages From: a domain publishing a ' 'DMARC policy of reject or quarantine or to all messages if ' 'DMARC Mitigate unconditionally is True.')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('DMARC Mitigate unconditionally'), help_text=_( 'If DMARC mitigation action is munge_from or wrap_message, ' 'should it apply to all messages regardless of the DMARC policy ' 'of the From: domain.')) label=_('DMARC rejection notice'), required=False, widget=forms.Textarea(), help_text=_( 'Text to replace the default reason in any rejection notice to ' 'be sent when DMARC mitigation action of reject applies.')) label=_('DMARC wrapped message text'), required=False, widget=forms.Textarea(), help_text=_( 'Text to be added as a separate text/plain MIME part preceding ' 'the original message part in the wrapped message when DMARC ' 'mitigation action of wrap message applies.'))
""" Alter messages list settings. """ choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Filter content'), help_text=_('Should Mailman filter the content of list traffic ' 'according to the settings below?')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Collapse alternatives'), help_text=_('Should Mailman collapse multipart/alternative to ' 'its first part content?')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Convert html to plaintext'), help_text=_('Should Mailman convert text/html parts to plain text? ' 'This conversion happens after MIME attachments ' 'have been stripped.')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Anonymous list'), help_text=_('Hide the sender of a message, ' 'replacing it with the list address ' '(Removes From, Sender and Reply-To fields)')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Include RFC2369 headers'), help_text=_( 'Yes is highly recommended. RFC 2369 defines a set of List-* ' 'headers that are normally added to every message sent to the ' 'list membership. These greatly aid end-users who are using ' 'standards compliant mail readers. They should normally always ' 'be enabled. However, not all mail readers are standards ' 'compliant yet, and if you have a large number of members who are ' 'using non-compliant mail readers, they may be annoyed at these ' 'headers. You should first try to educate your members as to why ' 'these headers exist, and how to hide them in their mail clients. ' 'As a last resort you can disable these headers, but this is not ' 'recommended (and in fact, your ability to disable these headers ' 'may eventually go away).')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_("Include the list post header"), help_text=_( "This can be set to no for announce lists that do not wish to " "include the List-Post header because posting to the list is " "discouraged.")) label=_('Explicit reply-to address'), required=False, help_text=_( 'This option allows admins to set an explicit Reply-to address. ' 'It is only used if the reply-to is set to use an explicitly set ' 'header')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, help_text=_( 'Should any existing Reply-To: header found in the original ' 'message be stripped? If so, this will be done regardless of ' 'whether an explict Reply-To: header is added by Mailman or not.')) label=_('Reply goes to list'), widget=forms.Select(), required=False, error_messages={ 'required': _("Please choose a reply-to action.")}, choices=( ('no_munging', _('No Munging')), ('point_to_list', _('Reply goes to list')), ('explicit_header', _('Explicit Reply-to header set')), ('explicit_header_only', _('Explicit Reply-to set; no Cc added'))), help_text=_( 'Where are replies to list messages directed? No Munging is ' 'strongly recommended for most mailing lists. \nThis option ' 'controls what Mailman does to the Reply-To: header in messages ' 'flowing through this mailing list. When set to No Munging, no ' 'Reply-To: header is ' 'added by Mailman, although if one is present in the original ' 'message, it is not stripped. Setting this value to either Reply ' 'to List, Explicit Reply, or Reply Only causes Mailman to insert ' 'a specific Reply-To: header in all messages, overriding the ' 'header in the original message if necessary ' '(Explicit Reply inserts the value of reply_to_address). ' 'Explicit Reply-to set; no Cc added is useful for' 'announce-only lists where you want to avoid someone replying ' 'to the list address. There are many reasons not to introduce or ' 'override the Reply-To: header. One is that some posters depend ' 'on their own Reply-To: settings to convey their valid return ' 'address. Another is that modifying Reply-To: makes it much more ' 'difficult to send private replies. See `Reply-To\' Munging ' 'Considered Harmful for a general discussion of this issue. ' 'See Reply-To Munging Considered Useful for a dissenting opinion. ' 'Some mailing lists have restricted ' 'posting privileges, with a parallel list devoted to discussions. ' 'Examples are `patches\' or `checkin\' lists, where software ' 'changes are posted by a revision control system, but discussion ' 'about the changes occurs on a developers mailing list. To ' 'support these types of mailing lists, select Explicit Reply and ' 'set the Reply-To: address option to point to the parallel list.')) label=_('Pipeline'), widget=forms.Select(), required=False, choices=lambda: ((p, p) for p in get_mailman_client() .pipelines['pipelines']), help_text=_('Type of pipeline you want to use for this mailing list'))
""" List settings for automatic responses. """ ("respond_and_continue", _("Respond and continue processing")), ("respond_and_discard", _("Respond and discard message")), ("none", _("No automatic response"))) choices=autorespond_choices, widget=forms.RadioSelect, label=_('Autorespond to list owner'), help_text=_('Should Mailman send an auto-response to ' 'emails sent to the -owner address?')) label=_('Autoresponse owner text'), widget=forms.Textarea(), required=False, help_text=_('Auto-response text to send to -owner emails.')) choices=autorespond_choices, widget=forms.RadioSelect, label=_('Autorespond postings'), help_text=_('Should Mailman send an auto-response to ' 'mailing list posters?')) label=_('Autoresponse postings text'), widget=forms.Textarea(), required=False, help_text=_('Auto-response text to send to mailing list posters.')) choices=autorespond_choices, widget=forms.RadioSelect, label=_('Autorespond requests'), help_text=_( 'Should Mailman send an auto-response to emails sent to the ' '-request address? If you choose yes, decide whether you want ' 'Mailman to discard the original email, or forward it on to the ' 'system as a normal mail command.')) label=_('Autoresponse request text'), widget=forms.Textarea(), required=False, help_text=_('Auto-response text to send to -request emails.')) label=_('Autoresponse grace period'), help_text=_( 'Number of days between auto-responses to either the mailing list ' 'or -request/-owner address from the same poster. Set to zero ' '(or negative) for no grace period (i.e. auto-respond to every ' 'message).')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Notify users of held messages'), help_text=_( 'Should Mailman notify users about their messages held for ' 'approval. If you say \'No\', no notifications will be sent ' 'to users about the pending approval on their messages.')) choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, required=False, label=_('Send welcome message'), help_text=_( 'Send welcome message to newly subscribed members? ' 'Turn this off only if you plan on subscribing people manually ' 'and don\'t want them to know that you did so. Setting this to No ' 'is most useful for transparently migrating lists from some other ' 'mailing list manager to Mailman.\n' 'The text of Welcome message can be set via the Templates tab.')) widget=forms.RadioSelect(choices=((True, _('Yes')), (False, _('No')))), required=False, label=_('Admin immed notify'), help_text=_( 'Should the list moderators get immediate notice of new requests, ' 'as well as daily notices about collected ones? List moderators ' '(and list administrators) are sent daily reminders of requests ' 'pending approval, like subscriptions to a moderated list, ' 'or postings that are being held for one reason or another. ' 'Setting this option causes notices to be sent immediately on the ' 'arrival of new requests as well. ')) widget=forms.RadioSelect(choices=((True, _('Yes')), (False, _('No')))), required=False, label=_('Notify admin of membership changes'), help_text=_('Should administrator get notices of ' 'subscribes and unsubscribes?'))
""" List identity settings. """ choices=((True, _('Yes')), (False, _('No'))), widget=forms.RadioSelect, label=_('Show list on index page'), help_text=_('Choose whether to include this list ' 'on the list of all lists')) label=_('Description'), required=False, help_text=_( 'This description is used when the mailing list is listed with ' 'other mailing lists, or in headers, and so forth. It should be ' 'as succinct as you can get it, while still identifying what the ' 'list is.'), ) label=_('Information'), help_text=_('A longer description of this mailing list.'), required=False, widget=forms.Textarea()) label=_('Display name'), required=False, help_text=_('Display name is the name shown in the web interface.') ) label=_('Subject prefix'), strip=False, required=False, )
""" Strip the leading whitespaces from the subject_prefix form field. """
"""Form fields to masssubscribe users to a list. """ label=_('Emails to mass subscribe'), help_text=_( 'The following formats are accepted:\n' 'jdoe@example.com\n' '<jdoe@example.com>\n' 'John Doe <jdoe@example.com>\n' '"John Doe" <jdoe@example.com>\n' 'jdoe@example.com (John Doe)\n' 'Use the last three to associate a display name with the address\n' ), )
"""Form fields to remove multiple list users. """ label=_('Emails to Unsubscribe'), help_text=_('Add one email address on each line'), )
""" Class to define the name of the fieldsets and what should be included in each. """
"""Ban an email address for a list.""" # TODO maxking: This form should only accept valid emails or regular # expressions. Anything else that doesn't look like a valid email address # or regexp for email should not be a valid value for the field. However, # checking for that might not be easy. label=_('Add ban'), help_text=_( 'You can ban a single email address or use a regular expression ' 'to match similar email addresses.'), error_messages={ 'required': _('Please enter an email address.'), 'invalid': _('Please enter a valid email address.')})
"""Edit a list's header match."""
[a for a in ACTION_CHOICES if a[0] != 'defer']
label=_('Header'), help_text=_('Email header to filter on (case-insensitive).'), error_messages={ 'required': _('Please enter a header.'), 'invalid': _('Please enter a valid header.')}) label=_('Pattern'), help_text=_('Regular expression matching the header\'s value.'), error_messages={ 'required': _('Please enter a pattern.'), 'invalid': _('Please enter a valid pattern.')}) label=_('Action'), error_messages={'invalid': _('Please enter a valid action.')}, required=False, choices=HM_ACTION_CHOICES, help_text=_('Action to take when a header matches') )
"""Checks that no two header matches have the same order.""" # Don't bother validating the formset unless # each form is valid on its own ' distinct orders.')
""" Form handling the member's moderation_action. """ widget=forms.Select(), label=_('Moderation'), required=False, choices=[(None, _('List default'))] + list(ACTION_CHOICES), help_text=_( 'Default action to take when this member posts to the list. \n' 'List default -- follow the list\'s default member action. \n' 'Hold -- This holds the message for approval by the list ' 'moderators. \n' 'Reject -- this automatically rejects the message by sending a ' 'bounce notice to the post\'s author. The text of the bounce ' 'notice can be configured by you. \n' 'Discard -- this simply discards the message, with no notice ' 'sent to the post\'s author. \n' 'Accept -- accepts any postings without any further checks. \n' 'Default Processing -- run additional checks and accept ' 'the message. \n'))
label=_('Select Email'), required=False, widget=forms.Select(), choices=((address, address) for address in user_emails)) |