diff --git a/src/postorius/__init__.py b/src/postorius/__init__.py index c61a15b..e3a8b32 100644 --- a/src/postorius/__init__.py +++ b/src/postorius/__init__.py @@ -16,5 +16,4 @@ # You should have received a copy of the GNU General Public License along with # Postorius. If not, see . -__version__ = '1.0.0a1' - +__version__ = '1.0.0a2' diff --git a/src/postorius/context_processors.py b/src/postorius/context_processors.py index 694827d..d154682 100644 --- a/src/postorius/context_processors.py +++ b/src/postorius/context_processors.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 1998-2012 by the Free Software Foundation, Inc. +# Copyright (C) 2012 by the Free Software Foundation, Inc. # # This file is part of Postorius. # @@ -32,11 +32,9 @@ """ # extend_template (no page header/footer when requested via AJAX) if request.is_ajax(): - extend_template = "postorius/base_ajax.html" - else: + extend_template = "postorius/base_ajax.html" + else: extend_template = "postorius/base.html" - return { - 'MAILMAN_THEME': settings.MAILMAN_THEME, - 'extend_template': extend_template, - } + return {'MAILMAN_THEME': settings.MAILMAN_THEME, + 'extend_template': extend_template} diff --git a/src/postorius/doc/news.rst b/src/postorius/doc/news.rst index 91f0cc4..75b846d 100644 --- a/src/postorius/doc/news.rst +++ b/src/postorius/doc/news.rst @@ -33,6 +33,7 @@ * added list members view * added developer documentation * added test helper utils +* all code now conform to PEP8 1.0 alpha 1 -- "Space Farm" diff --git a/src/postorius/fieldset_forms.py b/src/postorius/fieldset_forms.py index 7bfa337..d4abadc 100644 --- a/src/postorius/fieldset_forms.py +++ b/src/postorius/fieldset_forms.py @@ -21,9 +21,11 @@ from django.forms.forms import BoundField from django.forms.util import ErrorList + class FieldsetError(Exception): pass + class FieldsetForm(Form): """ Extends a standard form and adds fieldsets and the possibililty @@ -41,14 +43,16 @@ self.layout = self.Meta.layout else: self.layout = [["All"]] - self.layout[0][1:]=(self.fields.keys()) - + self.layout[0][1:] = (self.fields.keys()) + def as_div(self): """Render the form as a set of
s.""" output = "" #Adding Errors - try: output += str(self.errors["NON_FIELD_ERRORS"]) - except: pass + try: + output += str(self.errors["NON_FIELD_ERRORS"]) + except: + pass #create the fieldsets for index in range(len(self.layout)): output += self.create_fieldset(self.layout[index]) @@ -61,9 +65,10 @@ it should include. """ # Create the divs in each fieldset by calling create_divs. - return u'
%s%s
' % (field[0], + return u'
%s%s
' % ( + field[0], self.create_divs(field[1:])) - + def create_divs(self, fields): """Create a
for each field.""" output = "" @@ -73,17 +78,18 @@ field_instance = self.fields[field] except KeyError: # could not create the instance so throw an exception - # msg on a separate line since the line got too long + # msg on a separate line since the line got too long # otherwise msg = "Could not resolve form field '%s'." % field raise FieldsetError(msg) - # create a bound field containing all the necessary fields + # create a bound field containing all the necessary fields # from the form bound_field = BoundField(self, field_instance, field) - output += '
%(label)s%(help_text)s%(errors)s%(field)s
\n' % \ - {'class': bound_field.name, - 'label': bound_field.label, - 'help_text': bound_field.help_text, - 'errors': bound_field.errors, - 'field': unicode(bound_field)} + output += '
%(label)s%(help_text)s%' \ + '(errors)s%(field)s
\n' % \ + {'class': bound_field.name, + 'label': bound_field.label, + 'help_text': bound_field.help_text, + 'errors': bound_field.errors, + 'field': unicode(bound_field)} return output diff --git a/src/postorius/forms.py b/src/postorius/forms.py index b340d01..69d2f47 100644 --- a/src/postorius/forms.py +++ b/src/postorius/forms.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 1998-2012 by the Free Software Foundation, Inc. +# Copyright (C) 2012 by the Free Software Foundation, Inc. # # This file is part of Postorius. # @@ -21,31 +21,28 @@ from django.utils.translation import gettext as _ from fieldset_forms import FieldsetForm -#Fieldsets for use within the views + class DomainNew(FieldsetForm): - """ + """ Form field to add a new domain """ mail_host = forms.CharField( - label = _('Mail Host'), - error_messages = {'required': _('Please a domain name'), - 'invalid': _('Please enter a valid domain name.')}, - required = True - ) + label=_('Mail Host'), + error_messages={'required': _('Please a domain name'), + 'invalid': _('Please enter a valid domain name.')}, + required=True) web_host = forms.CharField( - label = _('Web Host'), - error_messages = {'required': _('Please a domain name'), - 'invalid': _('Please enter a valid domain name.')}, - required = True - ) + label=_('Web Host'), + error_messages={'required': _('Please a domain name'), + 'invalid': _('Please enter a valid domain name.')}, + required=True) description = forms.CharField( - label = _('Description'), - required = False - ) + label=_('Description'), + required=False) info = forms.CharField( - label = _('Information'), - required = False - ) + label=_('Information'), + required=False) + def clean_mail_host(self): mail_host = self.cleaned_data['mail_host'] try: @@ -56,85 +53,78 @@ def clean_web_host(self): web_host = self.cleaned_data['web_host'] - try: + try: validate_email('mail@' + web_host) - except: + except: raise forms.ValidationError(_("Please enter a valid Web Host")) return web_host - + class Meta: """ 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 + + 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. """ layout = [["Please enter Details", "mail_host", "web_host", - "description",]] + "description"]] - + class ListNew(FieldsetForm): """ - Form fields to add a new list. Languages are hard coded which should + Form fields to add a new list. Languages are hard coded which should be replaced by a REST lookup of available languages. - """ + """ listname = forms.CharField( - label = _('List Name'), - required = True, - error_messages = {'required': _('Please enter a name for your list.'), - 'invalid': _('Please enter a valid list name.')} - ) - + label=_('List Name'), + required=True, + error_messages={'required': _('Please enter a name for your list.'), + 'invalid': _('Please enter a valid list name.')}) mail_host = forms.ChoiceField() - list_owner = forms.EmailField( - label = _('Inital list owner address'), - error_messages = { - 'required': _("Please enter the list owner's email address."), - }, - required = True) + label=_('Inital list owner address'), + error_messages={ + 'required': _("Please enter the list owner's email address.")}, + required=True) advertised = forms.ChoiceField( - widget = forms.RadioSelect(), - label = _('Advertise this list?'), - error_messages = { - 'required': _("Please choose a list type."), - }, - required = True, - choices = ( + 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")), - )) + (False, _("Hide this list in list index")))) description = forms.CharField( - label = _('Description'), - required = True) + label=_('Description'), + required=True) - def __init__(self,domain_choices, *args, **kwargs): - super(ListNew, self).__init__(*args, **kwargs) + def __init__(self, domain_choices, *args, **kwargs): + super(ListNew, self).__init__(*args, **kwargs) self.fields["mail_host"] = forms.ChoiceField( - widget = forms.Select(), - label = _('Mail Host'), - required = True, - choices = domain_choices, - error_messages = {'required': _("Choose an existing Domain."), - 'invalid':"ERROR-todo_forms.py" }#todo - ) - + widget=forms.Select(), + label=_('Mail Host'), + required=True, + choices=domain_choices, + error_messages={'required': _("Choose an existing Domain."), + 'invalid': "ERROR-todo_forms.py"}) + def clean_listname(self): - try: - validate_email(self.cleaned_data['listname']+'@example.net') - except: + try: + validate_email(self.cleaned_data['listname'] + '@example.net') + except: raise forms.ValidationError(_("Please enter a valid listname")) return self.cleaned_data['listname'] class Meta: """ 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 + + 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. """ layout = [["List Details", @@ -142,610 +132,527 @@ "mail_host", "list_owner", "description", - "advertised"],] + "advertised"], ] + class ListSubscribe(FieldsetForm): """Form fields to join an existing list. """ - email = forms.EmailField(label = _('Your email address'), - widget = forms.HiddenInput(), - error_messages = {'required': _('Please enter an email address.'), - 'invalid': _('Please enter a valid email address.')}) + email = forms.EmailField( + label=_('Your email address'), + widget=forms.HiddenInput(), + error_messages={'required': _('Please enter an email address.'), + 'invalid': _('Please enter a valid email address.')}) display_name = forms.CharField(label=_('Your name (optional)'), required=False) - + + class ListUnsubscribe(FieldsetForm): """Form fields to leave an existing list. """ - email = forms.EmailField(label = _('Your email address'), - widget = forms.HiddenInput(), - error_messages = { - 'required': _('Please enter an email address.'), + email = forms.EmailField( + label=_('Your email address'), + widget=forms.HiddenInput(), + error_messages={ + 'required': _('Please enter an email address.'), 'invalid': _('Please enter a valid email address.')}) + class ListSettings(FieldsetForm): """Form fields dealing with the list settings. """ choices = ((True, _('Yes')), (False, _('No'))) list_name = forms.CharField( - label = _('List Name'), - required = False, - ) + label=_('List Name'), + required=False) host_name = forms.CharField( - label = _('Domain host name'), - required = False, - ) + label=_('Domain host name'), + required=False) fqdn_listname = forms.CharField( - label = _('Fqdn listname'), - required = False, - ) + label=_('Fqdn listname'), + required=False) include_list_post_header = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Include list post header'), - ) + widget=forms.RadioSelect, + required=False, + label= _('Include list post header')) include_rfc2369_headers = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Include RFC2369 headers'), - ) + widget=forms.RadioSelect, + required=False, + label= _('Include RFC2369 headers')) autorespond_choices = ( ("none", _("No automatic response")), ("respond_and_discard", _("Respond and discard message")), - ("respond_and_continue", _("Respond and continue processing")), - ) + ("respond_and_continue", _("Respond and continue processing"))) autorespond_owner = forms.ChoiceField( - choices = autorespond_choices, - widget = forms.RadioSelect, - label = _('Autorespond to list owner'), - ) + choices=autorespond_choices, + widget=forms.RadioSelect, + label=_('Autorespond to list owner')) autoresponse_owner_text = forms.CharField( - label = _('Autoresponse owner text'), - widget = forms.Textarea(), - required = False, - ) + label=_('Autoresponse owner text'), + widget=forms.Textarea(), + required=False) autorespond_postings = forms.ChoiceField( - choices = autorespond_choices, - widget = forms.RadioSelect, - label = _('Autorespond postings'), - ) + choices=autorespond_choices, + widget=forms.RadioSelect, + label=_('Autorespond postings')) autoresponse_postings_text = forms.CharField( - label = _('Autoresponse postings text'), - widget = forms.Textarea(), - required = False, - ) + label=_('Autoresponse postings text'), + widget=forms.Textarea(), + required=False) autorespond_requests = forms.ChoiceField( - choices = autorespond_choices, - widget = forms.RadioSelect, - label = _('Autorespond requests'), - ) + choices=autorespond_choices, + widget=forms.RadioSelect, + label=_('Autorespond requests')) autoresponse_request_text = forms.CharField( - label = _('Autoresponse request text'), - widget = forms.Textarea(), - required = False, - ) + label=_('Autoresponse request text'), + widget=forms.Textarea(), + required=False) autoresponse_grace_period = forms.CharField( - label = _('Autoresponse grace period'), - ) + label=_('Autoresponse grace period')) bounces_address = forms.EmailField( - label = _('Bounces Address'), - required = False, - ) - #ban_list = forms.CharField( - #label = _('Ban list'), - #widget = forms.Textarea - #) - #bounce_info_stale_after = forms.CharField( - #label = _('Bounce info stale after'), - #) - #bounce_matching_headers = forms.CharField( - #label = _('Bounce matching headers'), - #) - #bounce_notify_owner_on_disable = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Bounce notify owner on disable'), - #) - #bounce_notify_owner_on_removal = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Bounce notify owner on removal'), - #) - #bounce_processing = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Bounce processing'), - #) - #bounce_score_threshold = forms.IntegerField( - #label = _('Bounce score threshold'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) - #bounce_score_threshold = forms.IntegerField( - #label = _('Bounce score threshold'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) - #bounce_unrecognized_goes_to_list_owner = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Bounce unrecognized goes to list owner'), - #) - #bounce_you_are_disabled_warnings = forms.IntegerField( - #label = _('Bounce you are disabled warnings'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) - #bounce_you_are_disabled_warnings_interval = forms.CharField( - #label = _('Bounce you are disabled warnings interval'), - #) - #archive = forms.BooleanField( - #widget = forms.RadioSelect(choices=choices), - #required = False, - #label = _('Archive'), - #) - #archive_private = forms.BooleanField( - #widget = forms.RadioSelect(choices=choices), - #required = False, - #label = _('Private Archive'), - #) + label=_('Bounces Address'), + required=False) + # ban_list = forms.CharField( + # label=_('Ban list'), + # widget=forms.Textarea) + # bounce_info_stale_after = forms.CharField( + # label=_('Bounce info stale after') ) + # bounce_matching_headers = forms.CharField( + # label=_('Bounce matching headers')) + # bounce_notify_owner_on_disable = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Bounce notify owner on disable')) + # bounce_notify_owner_on_removal = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Bounce notify owner on removal')) + # bounce_processing = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Bounce processing')) + # bounce_score_threshold = forms.IntegerField( + # label=_('Bounce score threshold'), + # error_messages={ + # 'invalid': _('Please provide an integer.')}) + # bounce_score_threshold = forms.IntegerField( + # label=_('Bounce score threshold'), + # error_messages={ + # 'invalid': _('Please provide an integer.')}) + # bounce_unrecognized_goes_to_list_owner = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Bounce unrecognized goes to list owner')) + # bounce_you_are_disabled_warnings = forms.IntegerField( + # label=_('Bounce you are disabled warnings'), + # error_messages={ + # 'invalid': _('Please provide an integer.')}) + # bounce_you_are_disabled_warnings_interval = forms.CharField( + # label=_('Bounce you are disabled warnings interval')) + # archive = forms.BooleanField( + # widget=forms.RadioSelect(choices=choices), + # required=False, + # label=_('Archive')) + # archive_private = forms.BooleanField( + # widget=forms.RadioSelect(choices=choices), + # required=False, + # label=_('Private Archive')) advertised = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - label = _('Advertise the existance of this list?'), - ) + widget=forms.RadioSelect, + label=_('Advertise the existance of this list?')) filter_content = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Filter content'), - ) + widget=forms.RadioSelect, + required=False, + label=_('Filter content')) collapse_alternatives = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Collapse alternatives'), - ) + widget=forms.RadioSelect, + required=False, + label=_('Collapse alternatives')) convert_html_to_plaintext = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Convert html to plaintext'), - ) - #default_member_moderation = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Default member moderation'), - #) + widget=forms.RadioSelect, + required=False, + label=_('Convert html to plaintext')) + # default_member_moderation = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Default member moderation')) action_choices = ( ("hold", _("Hold for moderator")), ("reject", _("Reject (with notification)")), ("discard", _("Discard (no notification)")), ("accept", _("Accept")), - ("defer", _("Defer")), - ) + ("defer", _("Defer"))) default_member_action = forms.ChoiceField( - 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, - ) + 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) default_nonmember_action = forms.ChoiceField( - 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, - ) + 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) description = forms.CharField( - label = _('Description'), - widget = forms.Textarea() - ) - #digest_footer = forms.CharField( - #label = _('Digest footer'), - #) - #digest_header = forms.CharField( - #label = _('Digest header'), - #) - #digest_is_default = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Digest is default'), - #) - #digest_send_periodic = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Digest send periodic'), - #) + label=_('Description'), + widget=forms.Textarea()) + # digest_footer = forms.CharField( + # label=_('Digest footer')) + # digest_header = forms.CharField( + # label=_('Digest header')) + # digest_is_default = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Digest is default')) + # digest_send_periodic = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Digest send periodic')) digest_size_threshold = forms.DecimalField( - label = _('Digest size threshold'), + label=_('Digest size threshold'), ) - #digest_volume_frequency = forms.CharField( - #label = _('Digest volume frequency'), - #) - #digestable = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Digestable'), - #) + # digest_volume_frequency = forms.CharField( + # label=_('Digest volume frequency')) + # digestable = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Digestable')) digest_last_sent_at = forms.IntegerField( - label = _('Digest last sent at'), - error_messages = { - 'invalid': _('Please provide an integer.'), - }, - required = False, - ) - #discard_these_nonmembers = forms.CharField( - #label = _('Discard these nonmembers'), - #widget = forms.Textarea - #) - #emergency = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Emergency'), - #) - #encode_ascii_prefixes = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Encode ascii prefixes'), - #) + label=_('Digest last sent at'), + error_messages={ + 'invalid': _('Please provide an integer.')}, + required=False) + # discard_these_nonmembers = forms.CharField( + # label=_('Discard these nonmembers'), + # widget=forms.Textarea) + # emergency = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Emergency')) + # encode_ascii_prefixes = forms.BooleanField( + # widget=forms.RadioSelect(choices = choices), + # required=False, + # label=_('Encode ascii prefixes')) #first_strip_reply_to = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('First strip reply to'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('First strip reply to'), #) #forward_auto_discards = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Forward auto discards'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Forward auto discards'), #) #gateway_to_mail = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Gateway to mail'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Gateway to mail'), #) #gateway_to_news = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Gateway to news'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Gateway to news'), #) generic_nonmember_action = forms.IntegerField( - label = _('Generic nonmember action'), - error_messages = { + label=_('Generic nonmember action'), + error_messages={ 'invalid': _('Please provide an integer.') } ) #goodbye_msg = forms.CharField( - #label = _('Goodbye message'), + #label=_('Goodbye message'), #) #header_matches = forms.CharField( - #label = _('Header matches'), - #widget = forms.Textarea + #label=_('Header matches'), + #widget=forms.Textarea #) #hold_these_nonmembers = forms.CharField( - #label = _('Hold these nonmembers'), - #widget = forms.Textarea + #label=_('Hold these nonmembers'), + #widget=forms.Textarea #) #info = forms.CharField( - #label = _('Information'), + #label=_('Information'), #) #linked_newsgroup = forms.CharField( - #label = _('Linked newsgroup'), + #label=_('Linked newsgroup'), #) mail_host = forms.CharField( - label = _('Mail Host'), - error_messages = {'required': _('Please a domain name'), - 'invalid': _('Please enter a valid domain name.')}, - required = True - ) + label=_('Mail Host'), + error_messages={'required': _('Please a domain name'), + 'invalid': _('Please enter a valid domain name.')}, + required=True) #max_days_to_hold = forms.IntegerField( - #label = _('Maximum days to hold'), - #error_messages = { + #label=_('Maximum days to hold'), + #error_messages={ #'invalid': _('Please provide an integer.') #} #) #max_message_size = forms.IntegerField( - #label = _('Maximum message size'), - #error_messages = { + #label=_('Maximum message size'), + #error_messages={ #'invalid': _('Please provide an integer.') #} #) #max_num_recipients = forms.IntegerField( - #label = _('Maximum number of recipients'), - #error_messages = { + #label=_('Maximum number of recipients'), + #error_messages={ #'invalid': _('Please provide an integer.') #} #) #member_moderation_action = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Member moderation action'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Member moderation action'), #) #member_moderation_notice = forms.CharField( - #label = _('Member moderation notice'), + #label=_('Member moderation notice'), #) #mime_is_default_digest = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Mime is default digest'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Mime is default digest'), #) #moderator_password = forms.CharField( - #label = _('Moderator password'), - #widget = forms.PasswordInput, - #error_messages = {'required': _('Please enter your password.'), + #label=_('Moderator password'), + #widget=forms.PasswordInput, + #error_messages={'required': _('Please enter your password.'), #'invalid': _('Please enter a valid password.')}, #) #msg_footer = forms.CharField( - #label = _('Message footer'), + #label=_('Message footer'), #) #msg_header = forms.CharField( - #label = _('Message header'), + #label=_('Message header'), #) #new_member_options = forms.IntegerField( - #label = _('New member options'), - #error_messages = { + #label=_('New member options'), + #error_messages={ #'invalid': _('Please provide an integer.') #} #) #news_moderation = forms.CharField( - #label = _('News moderation'), + #label=_('News moderation'), #) #news_prefix_subject_too = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('News prefix subject too'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('News prefix subject too'), #) #nntp_host = forms.CharField( - #label = _('Nntp host'), + #label=_('Nntp host'), #) #nondigestable = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Nondigestable'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Nondigestable'), #) #nonmember_rejection_notice = forms.CharField( - #label = _('Nonmember rejection notice'), + #label=_('Nonmember rejection notice'), #) next_digest_number = forms.IntegerField( - label = _('Next digest number'), - error_messages = { + label=_('Next digest number'), + error_messages={ 'invalid': _('Please provide an integer.'), }, - required = False, + required=False, ) no_reply_address = forms.EmailField( - label = _('No reply address'), - required = False, + label=_('No reply address'), + required=False, ) #obscure_addresses = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Obscure addresses'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Obscure addresses'), #) #personalize = forms.CharField( - #label = _('Personalize'), + #label=_('Personalize'), #) posting_pipeline = forms.CharField( - label = _('Pipeline'), + label=_('Pipeline'), ) post_id = forms.IntegerField( - label = _('Post ID'), - error_messages = { + label=_('Post ID'), + error_messages={ 'invalid': _('Please provide an integer.'), }, - required = False, + required=False, ) #preferred_language = forms.CharField( - #label = _('Preferred language'), + #label=_('Preferred language'), #) #private_roster = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Private roster'), + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Private roster'), #) display_name = forms.CharField( - label = _('Display name'), + label=_('Display name'), ) #reject_these_nonmembers = forms.CharField( - #label = _('Reject these nonmembers'), - #widget = forms.Textarea + #label=_('Reject these nonmembers'), + #widget=forms.Textarea #) - reply_goes_to_list = forms.ChoiceField( - label = _('Reply goes to list'), - widget = forms.Select(), - error_messages = { - 'required': _("Please choose a reply-to action."), - }, - choices = ( + label=_('Reply goes to list'), + widget=forms.Select(), + 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", _("Explicit Reply-to header set")))) #reply_to_address = forms.EmailField( - #label = _('Reply to address'), - #) + #label=_('Reply to address')) #require_explicit_destination = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Require explicit destination'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Require explicit destination')) #respond_to_post_requests = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Respond to post requests'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Respond to post requests')) request_address = forms.EmailField( - label = _('Request address'), - required = False, - ) + label=_('Request address'), + required=False) #scrub_nondigest = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Scrub nondigest'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Scrub nondigest')) #send_goodbye_msg = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Send goodbye message'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Send goodbye message')) #send_reminders = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Send reminders'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Send reminders')) send_welcome_message = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Send welcome message'), - ) + widget=forms.RadioSelect, + required=False, + label=_('Send welcome message')) #start_chain = forms.CharField( - #label = _('Start chain'), - #) + #label=_('Start chain')) #subject_prefix = forms.CharField( - #label = _('Subject prefix'), - #) + #label=_('Subject prefix')) #subscribe_auto_approval = forms.CharField( - #label = _('Subscribe auto approval'), - #widget = forms.Textarea - #) + #label=_('Subscribe auto approval'), + #widget=forms.Textarea) #subscribe_policy = forms.IntegerField( - #label = _('Subscribe policy'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) + #label=_('Subscribe policy'), + #error_messages={ + #'invalid': _('Please provide an integer.')}) scheme = forms.CharField( - label = _('Scheme'), - required = False, - ) + label=_('Scheme'), + required=False) #topics = forms.CharField( - #label = _('Topics'), - #widget = forms.Textarea - #) + #label=_('Topics'), + #widget=forms.Textarea) #topics_bodylines_limit = forms.IntegerField( - #label = _('Topics bodylines limit'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) + #label=_('Topics bodylines limit'), + #error_messages={ + #'invalid': _('Please provide an integer.')}) #topics_enabled = forms.BooleanField( - #widget = forms.RadioSelect(choices = choices), - #required = False, - #label = _('Topics enabled'), - #) + #widget=forms.RadioSelect(choices = choices), + #required=False, + #label=_('Topics enabled')#) #unsubscribe_policy = forms.IntegerField( - #label = _('Unsubscribe policy'), - #error_messages = { - #'invalid': _('Please provide an integer.') - #} - #) + #label=_('Unsubscribe policy'), + #error_messages={ + #'invalid': _('Please provide an integer.')}) #welcome_msg = forms.CharField( - #label = _('Welcome message'), - #) + #label=_('Welcome message')) #volume = forms.IntegerField( - # label = _('Volume'), - # required = False, - #) + # label=_('Volume'), + # required=False) #web_host = forms.CharField( - # label = _('Web host'), - # required = False, - #) + # label=_('Web host'), + # required=False) acceptable_aliases = forms.CharField( - widget = forms.Textarea(), - label = _("Acceptable aliases"), - required = False, - ) + widget=forms.Textarea(), + label=_("Acceptable aliases"), + required=False) admin_immed_notify = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Admin immed notify'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Admin immed notify')) admin_notify_mchanges = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Admin notify mchanges'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Admin notify mchanges')) administrivia = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Administrivia'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Administrivia')) anonymous_list = forms.TypedChoiceField( - coerce=lambda x: x =='True', + coerce=lambda x: x == 'True', choices=((True, _('Yes')), (False, _('No'))), - widget = forms.RadioSelect, - required = False, - label = _('Anonymous list'), - ) + widget=forms.RadioSelect, + required=False, + label=_('Anonymous list')) created_at = forms.IntegerField( - label = _('Created at'), - widget = forms.HiddenInput(), - required = False, - ) + label=_('Created at'), + widget=forms.HiddenInput(), + required=False) join_address = forms.EmailField( - label = _('Join address'), - required = False, - ) + label=_('Join address'), + required=False) last_post_at = forms.IntegerField( - label = _('Last post at'), - required = False, - ) + label=_('Last post at'), + required=False) leave_address = forms.EmailField( - label = _('Leave address'), - required = False, - ) + label=_('Leave address'), + required=False) owner_address = forms.EmailField( - label = _('Owner Address'), - required = False, - ) + label=_('Owner Address'), + required=False) posting_address = forms.EmailField( - label = _('Posting Address'), - required = False, - ) + label=_('Posting Address'), + required=False) #Descriptions used in the Settings Overview Page section_descriptions = { - "List Identity":_("Basic identity settings for the list"), - "Automatic Responses":_("All options for Autoreply"), - "Alter Messages":_("Settings that modify member messages"), + "List Identity": _("Basic identity settings for the list"), + "Automatic Responses": _("All options for Autoreply"), + "Alter Messages": _("Settings that modify member messages"), "Digest": _("Digest-related options"), - "Message Acceptance": _("Options related to accepting messages"), - } + "Message Acceptance": _("Options related to accepting messages")} + def clean_acceptable_aliases(self): data = self.cleaned_data['acceptable_aliases'] return data.splitlines() - def __init__(self,visible_section,visible_option, *args, **kwargs): - super(ListSettings, self).__init__(*args, **kwargs) - #if settings:raise Exception(settings) #debug + + def __init__(self, visible_section, visible_option, *args, **kwargs): + super(ListSettings, self).__init__(*args, **kwargs) + # if settings: + # raise Exception(settings) # debug if visible_option: - options=[] + options = [] for option in self.layout: options += option[1:] if visible_option in options: - self.layout = [["",visible_option]] + self.layout = [["", visible_option]] if visible_section: - sections=[] + sections = [] for section in self.layout: - sections.append(section[0]) + sections.append(section[0]) if visible_section in sections: for section in self.layout: if section[0] == visible_section: @@ -753,127 +660,79 @@ try: if data: for section in self.layout: - for option in section[1:]: + for option in section[1:]: self.fields[option].initial = settings[option] except: - pass #empty form + pass # empty form + def truncate(self): """ - truncates the form to have only those fields which are in self.layout + truncates the form to have only those fields which are in self.layout """ - #delete form.fields which are not in the layout - used_options=[] + # delete form.fields which are not in the layout + used_options = [] for section in self.layout: used_options += section[1:] - + for key in self.fields.keys(): if not(key in used_options): - del self.fields[key] - + del self.fields[key] + class Meta: """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 + + 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. - """ + """ # just a really temporary layout to see that it works. -- Anna layout = [ - ["List Identity", "display_name", "mail_host", "description", - "advertised"], - #"info", "list_name", "host_name", "list_id", "fqdn_listname", - #"http_etag", "volume", "web_host" + ["List Identity", "display_name", "mail_host", "description", + "advertised"], ["Automatic Responses", "autorespond_owner", "autoresponse_owner_text", "autorespond_postings", "autoresponse_postings_text", "autorespond_requests", "autoresponse_request_text", "autoresponse_grace_period", "send_welcome_message", "admin_immed_notify", "admin_notify_mchanges"], - ["Alter Messages", "filter_content", "collapse_alternatives", + ["Alter Messages", "filter_content", "collapse_alternatives", "convert_html_to_plaintext", "anonymous_list", "include_rfc2369_headers", "reply_goes_to_list", - "include_list_post_header", "posting_pipeline"], + "include_list_post_header", "posting_pipeline"], ["Digest", "digest_size_threshold"], - ["Message Acceptance", "acceptable_aliases", "administrivia", - "default_nonmember_action", "default_member_action"], - #["Bounce", "ban_list", - #"bounce_info_stale_after", "bounce_matching_headers", - # "bounce_notify_owner_on_disable", - #"bounce_notify_owner_on_removal", "bounce_processing", - #"bounce_score_threshold", - #"bounce_unrecognized_goes_to_list_owner", - #"bounce_you_are_disabled_warnings", - #"bounce_you_are_disabled_warnings_interval"], - #["Archiving", "archive"], - #["Content Filtering", "filter_content", "collapse_alternatives", - #"convert_html_to_plaintext"], - #"default_member_moderation", "scheme" - #["Digest", "digest_size_threshold"], #"next_digest_number", - #"last_post_at", "digest_last_sent_at", "digest_footer", - #"digest_header", "digest_is_default", - #"digest_send_periodic", "digest_size_threshold", - #"digest_volume_frequency", "digestable"], - #["Moderation","discard_these_nonmembers", "emergency", - #"generic_nonmember_action", "generic_nonmember_action", - #"member_moderation_action", "member_moderation_notice", - #"moderator_password", "hold_these_nonmembers"], - #["Message Text", "msg_header", "msg_footer", "welcome_msg", - #"goodbye_msg"], - #["Privacy", "advertised", "admin_immed_notify", - # "admin_notify_mchanges", "anonymous_list"], #"archive_private", - #"obscure_addresses", "private_roster", - #["Addresses", "bounces_address", "join_address", "leave_address", - #"no_reply_address", "owner_address", "posting_address", - #"request_address"], - #["Assorted", "acceptable_aliases", "administrivia", - #"posting_pipeline"] - #"post_id", "encode_ascii_prefixes", "first_strip_reply_to", - #"forward_auto_discards", "gateway_to_mail", "gateway_to_news", - #"header_matches", "linked_newsgroup", "max_days_to_hold", - #"max_message_size", "max_num_recipients", - #"mime_is_default_digest", "new_member_options", - #"news_moderation", "news_prefix_subject_too", "nntp_host", - #"nondigestable", "nonmember_rejection_notice", "personalize", - #"preferred_language", - #"reject_these_nonmembers", "reply_goes_to_list", - #"reply_to_address", "require_explicit_destination", - #"respond_to_post_requests", "scrub_nondigest", - #"send_goodbye_msg", "send_reminders", "send_welcome_msg", - #"start_chain", "subject_prefix", "subscribe_auto_approval", - #"subscribe_policy", "topics", "topics_bodylines_limit", - #"topics_enabled", "unsubscribe_policy"]] - ] + ["Message Acceptance", "acceptable_aliases", "administrivia", + "default_nonmember_action", "default_member_action"]] + class Login(FieldsetForm): """Form fields to let the user log in. """ user = forms.EmailField( - label = _('Email address'), - error_messages = {'required': _('Please enter an email address.'), - 'invalid': _('Please enter a valid email address.')}, - required = True, - ) + label=_('Email address'), + error_messages={'required': _('Please enter an email address.'), + 'invalid': _('Please enter a valid email address.')}, + required=True) password = forms.CharField( - label = _('Password'), - widget = forms.PasswordInput, - error_messages = {'required': _('Please enter your password.'), - 'invalid': _('Please enter a valid password.')}, - required = True, - ) + label=_('Password'), + widget=forms.PasswordInput, + error_messages={'required': _('Please enter your password.'), + 'invalid': _('Please enter a valid password.')}, + required=True) class Meta: """ Class to define the name of the fieldsets and what should be included in each. """ - layout = [["Login", "user", "password"],] + layout = [["Login", "user", "password"]] + class ListMassSubscription(FieldsetForm): """Form fields to masssubscribe users to a list. """ emails = forms.CharField( - label = _('Emails to mass subscribe'), - widget = forms.Textarea, + label=_('Emails to mass subscribe'), + widget=forms.Textarea, ) class Meta: @@ -881,142 +740,118 @@ Class to define the name of the fieldsets and what should be included in each. """ - layout = [["Mass subscription", "emails"],] + layout = [["Mass subscription", "emails"]] + class MembershipSettings(FieldsetForm): """Form handling the membership settings. """ - choices = ((True, _('Yes')), (False, _('No')),) + choices = ((True, _('Yes')), (False, _('No'))) acknowledge_posts = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Acknowledge posts'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Acknowledge posts')) hide_address = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Hide address'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Hide address')) receive_list_copy = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Receive list copy'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Receive list copy')) receive_own_postings = forms.BooleanField( - widget = forms.RadioSelect(choices = choices), - required = False, - label = _('Receive own postings'), - ) + widget=forms.RadioSelect(choices=choices), + required=False, + label=_('Receive own postings')) delivery_mode = forms.ChoiceField( - widget = forms.Select(), - error_messages = { - 'required': _("Please choose a mode."), - }, - required = False, - choices = ( + widget=forms.Select(), + error_messages={ + 'required': _("Please choose a mode.")}, + required=False, + choices=( ("", _("Please choose")), - ("delivery_mode", "some mode..."), # TODO: this must later - # be dynalically changed to what modes the list offers - # (see the address field in __init__ in UserSettings for - # how to do this) - ), - label = _('Delivery mode'), - ) + ("delivery_mode", "some mode...")), + label=_('Delivery mode')) delivery_status = forms.ChoiceField( - widget = forms.Select(), - error_messages = { - 'required': _("Please choose a status."), - }, - required = False, - choices = ( + widget=forms.Select(), + error_messages={ + 'required': _("Please choose a status.")}, + required=False, + choices=( ("", _("Please choose")), - ("delivery_status", "some status..."), # TODO: this must - # later be dynalically changed to what statuses the list - # offers (see the address field in __init__ in UserSettings - # for how to do this) - ), - label = _('Delivery status'), - ) + ("delivery_status", "some status...")), + label=_('Delivery status')) class Meta: """ Class to define the name of the fieldsets and what should be included in each. """ - layout = [["Membership Settings", "acknowledge_posts", "hide_address", - "receive_list_copy", "receive_own_postings", - "delivery_mode", "delivery_status"],] + layout = [["Membership Settings", "acknowledge_posts", "hide_address", + "receive_list_copy", "receive_own_postings", + "delivery_mode", "delivery_status"]] + class UserSettings(FieldsetForm): """Form handling the user settings. """ def __init__(self, address_choices, *args, **kwargs): """ - Initialize the user settings with a field 'address' where + Initialize the user settings with a field 'address' where the values are set dynamically in the view. """ super(UserSettings, self).__init__(*args, **kwargs) - self.fields['address'] = forms.ChoiceField(choices=(address_choices), - widget = forms.Select(), - error_messages = {'required': _("Please choose an address."),}, - required = True, - label = _('Default email address'),) - - id = forms.IntegerField( # this should probably not be - # changeable... - label = _('ID'), - initial = 9, - widget = forms.HiddenInput(), - required = False, - error_messages = { - 'invalid': _('Please provide an integer ID.') - } - ) - mailing_list = forms.CharField( # not sure this needs to be here - label = _('Mailing list'), - widget = forms.HiddenInput(), - required = False, - ) - display_name =forms.CharField( - label = _('Display name'), - required = False, - ) + self.fields['address'] = forms.ChoiceField( + choices=(address_choices), + widget=forms.Select(), + error_messages={'required': _("Please choose an address.")}, + required=True, + label=_('Default email address')) + + id = forms.IntegerField( + label=_('ID'), + initial=9, + widget=forms.HiddenInput(), + required=False, + error_messages={ + 'invalid': _('Please provide an integer ID.')}) + mailing_list = forms.CharField( + label=_('Mailing list'), + widget=forms.HiddenInput(), + required=False) + display_name = forms.CharField( + label=_('Display name'), + required=False) preferred_language = forms.ChoiceField( - label = _('Default/Preferred language'), - widget = forms.Select(), - error_messages = { - 'required': _("Please choose a language."), - }, - required = False, - choices = ( + label=_('Default/Preferred language'), + widget=forms.Select(), + error_messages={ + 'required': _("Please choose a language.")}, + required=False, + choices=( ("", _("Please choose")), - ("English (USA)", "English (USA)"), # TODO: this must later - # be dynalically changed to what languages the list offers - # (see the address field in __init__ for how to do this) - ) - ) + ("English (USA)", "English (USA)"))) password = forms.CharField( - label = _('Change password'), - widget = forms.PasswordInput, - required = False, - error_messages = {'required': _('Please enter your password.'), - 'invalid': _('Please enter a valid password.')}, - ) + label=_('Change password'), + widget=forms.PasswordInput, + required=False, + error_messages={'required': _('Please enter your password.'), + 'invalid': _('Please enter a valid password.')}) conf_password = forms.CharField( - label = _('Confirm password'), - widget = forms.PasswordInput, - required = False, - error_messages = {'required': _('Please enter your password.'), - 'invalid': _('Please enter a valid password.')}, - ) + label=_('Confirm password'), + widget=forms.PasswordInput, + required=False, + error_messages={'required': _('Please enter your password.'), + 'invalid': _('Please enter a valid password.')}) class Meta: """ Class to define the name of the fieldsets and what should be included in each. """ - layout = [["User settings", "display_name", "password", - "conf_password", "preferred_language", "address"],] + layout = [["User settings", "display_name", "password", + "conf_password", "preferred_language", "address"]] + class ListDeleteForm(forms.Form): list_name = forms.EmailField(widget=forms.HiddenInput()) diff --git a/src/postorius/models.py b/src/postorius/models.py index e1d4ab7..0899356 100644 --- a/src/postorius/models.py +++ b/src/postorius/models.py @@ -33,6 +33,7 @@ """ pass + class Mailman404Error(Exception): """Proxy exception. Raised if the API returns 404.""" pass @@ -42,7 +43,7 @@ """Manager class to give a model class CRUD access to the API. Returns objects (or lists of objects) retrived from the API. """ - + def __init__(self, resource_name, resource_name_plural, cls_name=None): self.client = Client('%s/3.0' % settings.REST_SERVER, settings.API_USER, settings.API_PASS) @@ -71,7 +72,6 @@ except MailmanConnectionError, e: raise MailmanApiError(e) - def get_or_404(self, **kwargs): """Similar to `self.get` but raises standard Django 404 error. """ @@ -143,7 +143,7 @@ self.kwargs = kwargs def save(self): - """Proxy function for `objects.create`. + """Proxy function for `objects.create`. (REST API uses `create`, while Django uses `save`.) """ self.objects.create(**self.kwargs) diff --git a/src/postorius/tests/__init__.py b/src/postorius/tests/__init__.py index 58acd95..e09dc1e 100644 --- a/src/postorius/tests/__init__.py +++ b/src/postorius/tests/__init__.py @@ -7,7 +7,7 @@ # 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 +# 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. diff --git a/src/postorius/tests/setup.py b/src/postorius/tests/setup.py index f334c07..ed533f4 100644 --- a/src/postorius/tests/setup.py +++ b/src/postorius/tests/setup.py @@ -23,11 +23,13 @@ import subprocess from django.conf import settings + class Testobject: bindir = None vardir = None cfgfile = None + def setup_mm(testobject): os.environ['MAILMAN_TEST_BINDIR'] = settings.MAILMAN_TEST_BINDIR bindir = testobject.bindir = os.environ.get('MAILMAN_TEST_BINDIR') @@ -37,7 +39,7 @@ cfgfile = testobject.cfgfile = os.path.join(vardir, 'client_test.cfg') with open(cfgfile, 'w') as fp: print >> fp, """\ -[mailman] +[mailman] layout: tmpdir [paths.tmpdir] var_dir: {vardir} @@ -70,6 +72,7 @@ time.sleep(3) return testobject + def teardown_mm(testobject): bindir = testobject.bindir cfgfile = testobject.cfgfile diff --git a/src/postorius/tests/test_list_members.py b/src/postorius/tests/test_list_members.py index 688612a..a23eb69 100644 --- a/src/postorius/tests/test_list_members.py +++ b/src/postorius/tests/test_list_members.py @@ -7,7 +7,7 @@ # 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 +# 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. @@ -22,12 +22,11 @@ class ListMembersViewTest(unittest.TestCase): """Tests for the ListMembersView.""" - + def setUp(self): from django.test.client import RequestFactory from postorius.tests.utils import create_mock_list, create_mock_member self.request_factory = RequestFactory() - # create a mock list with members list_name = 'foolist@example.org' self.mock_list = create_mock_list(dict( @@ -44,7 +43,6 @@ def test_get_list(self): """Test if list members are retreived correctly.""" from postorius.views import ListMembersView - # test get_list view = ListMembersView() with patch('mailman.client.Client.get_list') as mock: @@ -60,18 +58,23 @@ with patch('mailman.client.Client.get_list') as mock: mock.return_value = self.mock_list request = self.request_factory.get( - '/lists/foolist@example.org/members/') + '/lists/foolist@example.org/members/') # anonymous users should be redirected request.user = AnonymousUser() - response = ListMembersView.as_view()(request, 'foolist@example.org') + response = ListMembersView.as_view()(request, + 'foolist@example.org') self.assertEqual(response.status_code, 302) # logged in users should be redirected - request.user = User.objects.create_user('les', 'les@primus.org', 'pwd') - response = ListMembersView.as_view()(request, 'foolist@example.org') + request.user = User.objects.create_user('les', 'les@primus.org', + 'pwd') + response = ListMembersView.as_view()(request, + 'foolist@example.org') self.assertEqual(response.status_code, 302) # superusers should get the page - request.user = User.objects.create_superuser('su', 'su@sodo.org', 'pwd') - response = ListMembersView.as_view()(request, 'foolist@example.org') + request.user = User.objects.create_superuser('su', 'su@sodo.org', + 'pwd') + response = ListMembersView.as_view()(request, + 'foolist@example.org') self.assertEqual(response.status_code, 200) def tearDown(self): diff --git a/src/postorius/tests/test_utils.py b/src/postorius/tests/test_utils.py index db9ca0e..738acca 100644 --- a/src/postorius/tests/test_utils.py +++ b/src/postorius/tests/test_utils.py @@ -7,7 +7,7 @@ # 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 +# 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. diff --git a/src/postorius/tests/utils.py b/src/postorius/tests/utils.py index a6d1831..7dc7a4c 100644 --- a/src/postorius/tests/utils.py +++ b/src/postorius/tests/utils.py @@ -7,7 +7,7 @@ # 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 +# 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. @@ -17,15 +17,16 @@ from mock import patch, MagicMock + def create_mock_domain(properties=None): """Create and return a mocked Domain. - + :param properties: A dictionary of the domain's properties. :type properties: dict :return: A MagicMock object with the properties set. :rtype: MagicMock """ - mock_object = MagicMock(name='Domain') + mock_object = MagicMock(name='Domain') mock_object.base_url = '' mock_object.contact_address = '' mock_object.description = '' @@ -34,33 +35,35 @@ mock_object.lists = [] if properties is not None: for key in properties: - setattr(mock_object, key, properties[key]) + setattr(mock_object, key, properties[key]) return mock_object + def create_mock_list(properties=None): """Create and return a mocked List. - + :param properties: A dictionary of the list's properties. :type properties: dict :return: A MagicMock object with the properties set. :rtype: MagicMock """ - mock_object = MagicMock(name='List') + mock_object = MagicMock(name='List') if properties is not None: for key in properties: - setattr(mock_object, key, properties[key]) + setattr(mock_object, key, properties[key]) return mock_object + def create_mock_member(properties=None): """Create and return a mocked Member. - + :param properties: A dictionary of the member's properties. :type properties: dict :return: A MagicMock object with the properties set. :rtype: MagicMock """ - mock_object = MagicMock(name='Member') + mock_object = MagicMock(name='Member') if properties is not None: for key in properties: - setattr(mock_object, key, properties[key]) + setattr(mock_object, key, properties[key]) return mock_object diff --git a/src/postorius/urls.py b/src/postorius/urls.py index ac0e8d7..927d9a9 100644 --- a/src/postorius/urls.py +++ b/src/postorius/urls.py @@ -23,7 +23,8 @@ from postorius.views import ListMembersView -urlpatterns = patterns('postorius.views', +urlpatterns = patterns( + 'postorius.views', (r'^$', 'list_index'), # /account/ url(r'^accounts/login/$', 'user_login', name='user_login'), @@ -43,8 +44,8 @@ # /lists/ url(r'^lists/$', 'list_index', name='list_index'), url(r'^lists/new/$', 'list_new', name='list_new'), - url(r'^lists/(?P[^/]+)/members/$', ListMembersView.as_view(), - name='list_members'), + url(r'^lists/(?P[^/]+)/members/$', + ListMembersView.as_view(), name='list_members'), url(r'^lists/(?P[^/]+)/metrics$', 'list_metrics', name='list_metrics'), url(r'^lists/(?P[^/]+)/$', 'list_summary', @@ -57,27 +58,21 @@ 'list_subscriptions', name='list_subscriptions'), url(r'^lists/(?P[^/]+)/mass_subscribe/$', 'mass_subscribe', name='mass_subscribe'), - url(r'^lists/(?P[^/]+)/delete$', 'list_delete', - name='list_delete'), - url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/accept$', - 'accept_held_message', - name='accept_held_message'), - url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/discard$', - 'discard_held_message', - name='discard_held_message'), - url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/defer$', - 'defer_held_message', - name='defer_held_message'), - url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/reject$', - 'reject_held_message', - name='reject_held_message'), + url(r'^lists/(?P[^/]+)/delete$', + 'list_delete', name='list_delete'), + url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/' + 'accept$', 'accept_held_message', name='accept_held_message'), + url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/' + 'discard$', 'discard_held_message', name='discard_held_message'), + url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/' + 'defer$', 'defer_held_message', name='defer_held_message'), + url(r'^lists/(?P[^/]+)/held_messages/(?P[^/]+)/' + 'reject$', 'reject_held_message', name='reject_held_message'), url(r'^lists/(?P[^/]+)/held_messages$', - 'list_held_messages', - name='list_held_messages'), + 'list_held_messages', name='list_held_messages'), url(r'^user_settings/$', 'user_settings', kwargs={"tab": "user"}, name='user_settings'), - url(r'^lists/(?P[^/]+)/settings/(?P[^/]+)?(?:/(?P.*))?$', - 'list_settings', name='list_settings'), - ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - - + url(r'^lists/(?P[^/]+)/settings/(?P[^/]+)?' + '(?:/(?P.*))?$', 'list_settings', + name='list_settings'), +) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/src/postorius/utils.py b/src/postorius/utils.py index 698c6b6..b305a5a 100644 --- a/src/postorius/utils.py +++ b/src/postorius/utils.py @@ -22,16 +22,17 @@ def get_domain_name(request): """Extracts a domain name from the request object. - """ + """ if "HTTP_HOST" in request.META.keys(): return request.META["HTTP_HOST"].split(":")[0] return None + def render_api_error(request): """Renders an error template. Use if MailmanApiError is catched. """ - return render_to_response('postorius/errors/generic.html', - {'error': "REST API not found / Offline"}, - context_instance=RequestContext(request)) - + return render_to_response( + 'postorius/errors/generic.html', + {'error': "REST API not found / Offline"}, + context_instance=RequestContext(request)) diff --git a/src/postorius/views.py b/src/postorius/views.py index 3de56c2..d8db9d8 100644 --- a/src/postorius/views.py +++ b/src/postorius/views.py @@ -53,7 +53,8 @@ @user_passes_test(lambda u: u.is_superuser) def site_settings(request): return render_to_response('postorius/site_settings.html', - context_instance=RequestContext(request)) + context_instance=RequestContext(request)) + @login_required @user_passes_test(lambda u: u.is_superuser) @@ -63,8 +64,9 @@ except MailmanApiError: return utils.render_api_error(request) return render_to_response('postorius/domain_index.html', - {'domains':existing_domains,}, - context_instance=RequestContext(request)) + {'domains': existing_domains}, + context_instance=RequestContext(request)) + @login_required @user_passes_test(lambda u: u.is_superuser) @@ -81,14 +83,14 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e) + messages.error(request, e) else: - messages.success(request,_("New Domain registered")) + messages.success(request, _("New Domain registered")) return redirect("domain_index") else: form = DomainNew() return render_to_response('postorius/domain_new.html', - {'form': form,'message': message}, + {'form': form, 'message': message}, context_instance=RequestContext(request)) @@ -109,11 +111,11 @@ @login_required @user_passes_test(lambda u: u.is_superuser) -def list_new(request, template = 'postorius/lists/new.html'): +def list_new(request, template='postorius/lists/new.html'): """ - Add a new mailing list. - If the request to the function is a GET request an empty form for - creating a new list will be displayed. If the request method is + Add a new mailing list. + If the request to the function is a GET request an empty form for + creating a new list will be displayed. If the request method is POST the form will be evaluated. If the form is considered correct the list gets created and otherwise the form with the data filled in before the last POST request is returned. The user must @@ -125,7 +127,7 @@ domains = Domain.objects.all() except MailmanApiError: return utils.render_api_error(request) - choosable_domains = [("",_("Choose a Domain"))] + choosable_domains = [("", _("Choose a Domain"))] for domain in domains: choosable_domains.append((domain.mail_host, domain.mail_host)) @@ -149,10 +151,10 @@ fqdn_listname=mailing_list.fqdn_listname) #TODO catch correct Error class: except HTTPError, e: - messages.error(request,e) - return render_to_response('postorius/errors/generic.html', - {'error':e}, - context_instance=RequestContext(request)) + messages.error(request, e) + return render_to_response( + 'postorius/errors/generic.html', + {'error': e}, context_instance=RequestContext(request)) else: messages.success(_("New List created")) else: @@ -160,15 +162,16 @@ domains = Domain.objects.all() except MailmanApiError: return utils.render_api_error(request) - choosable_domains = [("",_("Choose a Domain"))] + choosable_domains = [("", _("Choose a Domain"))] for domain in domains: - choosable_domains.append((domain.mail_host,domain.mail_host)) + choosable_domains.append((domain.mail_host, domain.mail_host)) form = ListNew(choosable_domains, initial={'list_owner': request.user.email}) return render_to_response(template, {'form': form}, context_instance=RequestContext(request)) -def list_index(request, template = 'postorius/lists/index.html'): + +def list_index(request, template='postorius/lists/index.html'): """Show a table of all public mailing lists. """ lists = [] @@ -186,11 +189,12 @@ else: return render_to_response(template, {'error': error, - 'lists': lists,}, + 'lists': lists}, context_instance=RequestContext(request)) + @user_passes_test(lambda u: u.is_superuser) -def list_metrics(request,fqdn_listname=None,option=None, +def list_metrics(request, fqdn_listname=None, option=None, template='postorius/lists/metrics.html'): """ PUBLIC @@ -198,7 +202,7 @@ information about the list such as the date of the last post and the time the last digest is sent. """ - error=None + error = None user_is_subscribed = False if request.method == 'POST': return redirect("list_summary", fqdn_listname=request.POST["list"]) @@ -209,16 +213,15 @@ the_list.get_member(request.user.username) user_is_subscribed = True except: - pass #init + pass # init except MailmanApiError: return utils.render_api_error(request) return render_to_response(template, - {'list':the_list, - 'message': None, - 'user_is_subscribed':user_is_subscribed, - }, - context_instance=RequestContext(request) - ) + {'list': the_list, + 'message': None, + 'user_is_subscribed': user_is_subscribed}, + context_instance=RequestContext(request)) + def list_summary(request, fqdn_listname, option=None): """ @@ -229,12 +232,13 @@ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname) except MailmanApiError: return utils.render_api_error(request) - return render_to_response('postorius/lists/summary.html', + return render_to_response( + 'postorius/lists/summary.html', {'list': the_list, - 'subscribe_form': ListSubscribe( - initial={'email':user_email}),}, + 'subscribe_form': ListSubscribe(initial={'email': user_email})}, context_instance=RequestContext(request)) + @login_required def list_subscribe(request, fqdn_listname): """Subscribe to a list. @@ -247,7 +251,8 @@ email = request.POST.get('email') display_name = request.POST.get('display_name') the_list.subscribe(email, display_name) - messages.success(request, + messages.success( + request, _('You are subscribed to %s.' % the_list.fqdn_listname)) return redirect('list_summary', the_list.fqdn_listname) else: @@ -257,12 +262,13 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e.msg) + messages.error(request, e.msg) return redirect('list_summary', the_list.fqdn_listname) - return render_to_response('postorius/lists/subscribe.html', - {'form': form, 'list': the_list,}, + return render_to_response('postorius/lists/subscribe.html', + {'form': form, 'list': the_list}, context_instance=RequestContext(request)) + @login_required def list_unsubscribe(request, fqdn_listname, email): """Unsubscribe from a list. @@ -279,17 +285,19 @@ messages.error(request, e) return redirect('list_summary', the_list.fqdn_listname) + @login_required def list_subscriptions(request, option=None, fqdn_listname=None, - user_email=None, - template='postorius/lists/subscriptions.html', *args, **kwargs): + user_email=None, + template='postorius/lists/subscriptions.html', + *args, **kwargs): """ - Display the information there is available for a list. This - function also enables subscribing or unsubscribing a user to a - list. For the latter two different forms are available for the + Display the information there is available for a list. This + function also enables subscribing or unsubscribing a user to a + list. For the latter two different forms are available for the user to fill in which are evaluated in this function. """ - #create Values for Template usage + # create Values for Template usage message = None error = None form_subscribe = None @@ -300,10 +308,10 @@ try: the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname) except AttributeError, e: - return render_to_response('postorius/errors/generic.html', + return render_to_response('postorius/errors/generic.html', {'error': "REST API not found / Offline"}, context_instance=RequestContext(request)) - #process submitted form + # process submitted form if request.method == 'POST': form = False # The form enables both subscribe and unsubscribe. As a result @@ -314,18 +322,20 @@ # the form was valid so try to subscribe the user try: email = form.cleaned_data['email'] - response = the_list.subscribe(address=email, + response = the_list.subscribe( + address=email, display_name=form.cleaned_data.get('display_name', '')) - return render_to_response('postorius/lists/summary.html', - {'list': the_list, - 'option':option, - 'message':_("Subscribed ") + email }, - context_instance=RequestContext(request)) + return render_to_response( + 'postorius/lists/summary.html', + {'list': the_list, 'option': option, + 'message': _("Subscribed ") + email}, + context_instance=RequestContext(request)) except HTTPError, e: - return render_to_response('postorius/errors/generic.html', - {'error':e}, - context_instance=RequestContext(request)) - else: #invalid subscribe form + return render_to_response( + 'postorius/errors/generic.html', + {'error': e}, + context_instance=RequestContext(request)) + else: # invalid subscribe form form_subscribe = form form_unsubscribe = ListUnsubscribe( initial={'fqdn_listname': fqdn_listname, @@ -333,46 +343,49 @@ elif request.POST.get('name', '') == "unsubscribe": form = ListUnsubscribe(request.POST) if form.is_valid(): - #the form was valid so try to unsubscribe the user + # the form was valid so try to unsubscribe the user try: email = form.cleaned_data["email"] response = the_list.unsubscribe(address=email) - return render_to_response('postorius/lists/summary.html', - {'list': the_list, - 'message':_("Unsubscribed ") + email }, - context_instance=RequestContext(request)) + return render_to_response( + 'postorius/lists/summary.html', + {'list': the_list, + 'message': _("Unsubscribed ") + email}, + context_instance=RequestContext(request)) except ValueError, e: - return render_to_response('postorius/errors/generic.html', - {'error': e}, - context_instance=RequestContext(request)) - else:#invalid unsubscribe form + return render_to_response( + 'postorius/errors/generic.html', + {'error': e}, + context_instance=RequestContext(request)) + else: # invalid unsubscribe form form_subscribe = ListSubscribe( initial={'fqdn_listname': fqdn_listname, - 'option':option, - 'name' : 'subscribe'}) + 'option': option, + 'name': 'subscribe'}) form_unsubscribe = ListUnsubscribe(request.POST) else: # the request was a GET request so set the two forms to empty # forms - if option=="subscribe" or not option: + if option == "subscribe" or not option: form_subscribe = ListSubscribe( initial={'fqdn_listname': fqdn_listname, - 'email': request.user.username, - 'name' : 'subscribe'}) - if option=="unsubscribe" or not option: + 'email': request.user.username, + 'name': 'subscribe'}) + if option == "unsubscribe" or not option: form_unsubscribe = ListUnsubscribe( initial={'fqdn_listname': fqdn_listname, - 'email':request.user.username, - 'name' : 'unsubscribe'}) + 'email': request.user.username, + 'name': 'unsubscribe'}) the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname) return render_to_response(template, {'form_subscribe': form_subscribe, 'form_unsubscribe': form_unsubscribe, - 'message':message, - 'error':error, - 'list': the_list,}, + 'message': message, + 'error': error, + 'list': the_list}, context_instance=RequestContext(request)) + @login_required @user_passes_test(lambda u: u.is_superuser) def list_delete(request, fqdn_listname): @@ -391,11 +404,12 @@ submit_url = reverse('list_delete', kwargs={'fqdn_listname': fqdn_listname}) cancel_url = reverse('list_index',) - return render_to_response('postorius/confirm_dialog.html', - {'submit_url': submit_url, - 'cancel_url': cancel_url, - 'list':the_list,}, - context_instance=RequestContext(request)) + return render_to_response( + 'postorius/confirm_dialog.html', + {'submit_url': submit_url, 'cancel_url': cancel_url, + 'list': the_list}, + context_instance=RequestContext(request)) + @user_passes_test(lambda u: u.is_superuser) def list_held_messages(request, fqdn_listname): @@ -406,8 +420,9 @@ except MailmanApiError: return utils.render_api_error(request) return render_to_response('postorius/lists/held_messages.html', - {'list':the_list,}, - context_instance=RequestContext(request)) + {'list': the_list}, + context_instance=RequestContext(request)) + @user_passes_test(lambda u: u.is_superuser) def accept_held_message(request, fqdn_listname, msg_id): @@ -419,11 +434,12 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e.msg) + messages.error(request, e.msg) return redirect('list_held_messages', the_list.fqdn_listname) messages.success(request, 'The message has been accepted.') return redirect('list_held_messages', the_list.fqdn_listname) + @user_passes_test(lambda u: u.is_superuser) def discard_held_message(request, fqdn_listname, msg_id): """Accepts a held message. @@ -434,11 +450,12 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e.msg) + messages.error(request, e.msg) return redirect('list_held_messages', the_list.fqdn_listname) messages.success(request, 'The message has been discarded.') return redirect('list_held_messages', the_list.fqdn_listname) + @user_passes_test(lambda u: u.is_superuser) def defer_held_message(request, fqdn_listname, msg_id): """Accepts a held message. @@ -449,11 +466,12 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e.msg) + messages.error(request, e.msg) return redirect('list_held_messages', the_list.fqdn_listname) messages.success(request, 'The message has been defered.') return redirect('list_held_messages', the_list.fqdn_listname) + @user_passes_test(lambda u: u.is_superuser) def reject_held_message(request, fqdn_listname, msg_id): """Accepts a held message. @@ -464,11 +482,12 @@ except MailmanApiError: return utils.render_api_error(request) except HTTPError, e: - messages.error(request,e.msg) + messages.error(request, e.msg) return redirect('list_held_messages', the_list.fqdn_listname) messages.success(request, 'The message has been rejected.') return redirect('list_held_messages', the_list.fqdn_listname) + @login_required @user_passes_test(lambda u: u.is_superuser) def list_settings(request, fqdn_listname=None, visible_section=None, @@ -476,9 +495,9 @@ template='postorius/lists/settings.html'): """ View and edit the settings of a list. - The function requires the user to be logged in and have the + The function requires the user to be logged in and have the permissions necessary to perform the action. - + Use // to show only parts of the settings is optional / is used to differ in between section and option might @@ -486,7 +505,7 @@ """ message = "" logger.debug(visible_section) - if visible_section == None: + if visible_section is None: visible_section = 'List Identity' form_sections = [] try: @@ -494,53 +513,54 @@ except MailmanApiError: return utils.render_api_error(request) #collect all Form sections for the links: - temp = ListSettings('','') + temp = ListSettings('', '') for section in temp.layout: try: form_sections.append((section[0], temp.section_descriptions[section[0]])) except KeyError, e: - error=e + error = e del temp - #Save a Form Processed by POST + # Save a Form Processed by POST if request.method == 'POST': - form = ListSettings(visible_section,visible_option,data=request.POST) + form = ListSettings(visible_section, visible_option, data=request.POST) form.truncate() if form.is_valid(): list_settings = the_list.settings for key in form.fields.keys(): list_settings[key] = form.cleaned_data[key] - list_settings.save() + list_settings.save() message = _("The list has been updated.") else: message = _("Validation Error - The list has not been updated.") - else: #Provide a form with existing values #create form and process layout into form.layout - form = ListSettings(visible_section,visible_option,data=None) + form = ListSettings(visible_section, visible_option, data=None) #create a Dict of all settings which are used in the form - used_settings={} + used_settings = {} for section in form.layout: for option in section[1:]: used_settings[option] = the_list.settings[option] if option == u'acceptable_aliases': used_settings[option] = '\n'.join(used_settings[option]) - #recreate the form using the settings - form = ListSettings(visible_section,visible_option,data=used_settings) + # recreate the form using the settings + form = ListSettings(visible_section, visible_option, + data=used_settings) form.truncate() return render_to_response(template, {'form': form, 'form_sections': form_sections, 'message': message, 'list': the_list, - 'visible_option':visible_option, - 'visible_section':visible_section,}, + 'visible_option': visible_option, + 'visible_section': visible_section}, context_instance=RequestContext(request)) + @login_required @user_passes_test(lambda u: u.is_superuser) -def mass_subscribe(request, fqdn_listname=None, +def mass_subscribe(request, fqdn_listname=None, template='postorius/lists/mass_subscribe.html'): """ Mass subscribe users to a list. @@ -565,7 +585,8 @@ message = "The mass subscription was successful." except HTTPError, e: messages.error(request, e) - return redirect('mass_subscribe', the_list.fqdn_listname) + return redirect('mass_subscribe', + the_list.fqdn_listname) else: message = "Please enter valid email addresses." return redirect('mass_subscribe', the_list.fqdn_listname) @@ -577,6 +598,7 @@ 'list': the_list}, context_instance=RequestContext(request)) + @login_required def user_mailmansettings(request): try: @@ -586,30 +608,32 @@ settingsform = MembershipSettings() return render_to_response('postorius/user_mailmansettings.html', - {'mm_user': the_user, + {'mm_user': the_user, 'settingsform': settingsform}, context_instance=RequestContext(request)) + @login_required def membership_settings(request): """Display a list of all memberships. """ + @login_required -def user_settings(request, tab = "membership", - template = 'postorius/user_settings.html', - fqdn_listname = None,): +def user_settings(request, tab="membership", + template='postorius/user_settings.html', + fqdn_listname=None): """ Change the user or the membership settings. The user must be logged in to be allowed to change any settings. TODO: * add CSS to display tabs ?? - * add missing functionality in REST server and client and + * add missing functionality in REST server and client and change to the correct calls here """ member = request.user.username message = '' form = None - the_list=None + the_list = None membership_lists = [] try: @@ -621,28 +645,30 @@ user_object = the_list.get_member(member) else: message = ("") - for mlist in List.objects.all(): - try: + for mlist in List.objects.all(): + try: mlist.get_member(member) membership_lists.append(mlist) except: pass else: - # address_choices for the 'address' field must be a list of - # tuples of length 2 - raise Exception("") - address_choices = [[addr, addr] for addr in user_object.address] + # address_choices for the 'address' field must be a list of + # tuples of length 2 + raise Exception("") + address_choices = [[addr, addr] for addr in user_object.address] except AttributeError, e: - return render_to_response('postorius/errors/generic.html', - {'error': str(e)+"REST API not found / Offline"}, - context_instance=RequestContext(request)) + return render_to_response( + 'postorius/errors/generic.html', + {'error': str(e) + "REST API not found / Offline"}, + context_instance=RequestContext(request)) except ValueError, e: - return render_to_response('postorius/errors/generic.html', + return render_to_response('postorius/errors/generic.html', {'error': e}, context_instance=RequestContext(request)) - except HTTPError,e : - return render_to_response('postorius/errors/generic.html', - {'error': _("List ")+fqdn_listname+_(" does not exist")}, + except HTTPError, e: + return render_to_response( + 'postorius/errors/generic.html', + {'error': _("List ") + fqdn_listname + _(" does not exist")}, context_instance=RequestContext(request)) #----------------------------------------------------------------- if request.method == 'POST': @@ -660,23 +686,23 @@ # the 'address' field need choices as a tuple of length 2 addr_choices = [[request.POST["address"], request.POST["address"]]] form = UserSettings(addr_choices, request.POST) - if form.is_valid(): + if form.is_valid(): user_object.update(request.POST) - # to get the full list of addresses we need to + # to get the full list of addresses we need to # reinstantiate the form with all the addresses # TODO: should return the correct settings from the DB, - # not just the address_choices (add mock data to _User + # not just the address_choices (add mock data to _User # class and make the call with 'user_object.info') form = UserSettings(address_choices) message = "The user settings have been updated." else: - if tab == "membership" and fqdn_listname : + if tab == "membership" and fqdn_listname: if fqdn_listname: - #TODO : fix LP:821069 in mailman.client + # TODO : fix LP:821069 in mailman.client the_list = List.objects.get(fqdn_listname=fqdn_listname) member_object = the_list.get_member(member) - # TODO: add delivery_mode and deliver_status from a + # TODO: add delivery_mode and deliver_status from a # list of tuples at one point, currently we hard code # them in forms.py # instantiate the form with the correct member info @@ -688,15 +714,15 @@ delivery_mode delivery_status """ - data = {} #Todo https://bugs.launchpad.net/mailman/+bug/821438 + data = {} form = MembershipSettings(data) elif tab == "user": # TODO: should return the correct settings from the DB, - # not just the address_choices (add mock data to _User + # not just the address_choices (add mock data to _User # class and make the call with 'user_object._info') The 'language' # field must also be added as a list of tuples with correct # values (is currently hard coded in forms.py). - data ={}#Todo https://bugs.launchpad.net/mailman/+bug/821438 + data = {} # Todo https://bugs.launchpad.net/mailman/+bug/821438 form = UserSettings(data) return render_to_response(template, @@ -708,11 +734,13 @@ 'member': member}, context_instance=RequestContext(request)) + def user_logout(request): logout(request) return redirect('user_login') -def user_login(request,template = 'postorius/login.html'): + +def user_login(request, template='postorius/login.html'): if request.method == 'POST': form = AuthenticationForm(request.POST) user = authenticate(username=request.POST.get('username'), @@ -720,15 +748,16 @@ if user is not None: logger.debug(user) if user.is_active: - login(request,user) + login(request, user) return redirect(request.GET.get('next', 'list_index')) else: form = AuthenticationForm() - return render_to_response(template, {'form': form,}, + return render_to_response(template, {'form': form}, context_instance=RequestContext(request)) + @login_required -def user_profile(request, user_email = None): +def user_profile(request, user_email=None): if not request.user.is_authenticated(): return redirect('user_login') #try: @@ -736,11 +765,11 @@ #except MailmanApiError: # return utils.render_api_error(request) return render_to_response('postorius/user_profile.html', - # {'mm_user': the_user}, + # {'mm_user': the_user}, context_instance=RequestContext(request)) - + + @login_required def user_todos(request): return render_to_response('postorius/user_todos.html', context_instance=RequestContext(request)) -