diff --git a/fieldset_forms.py b/fieldset_forms.py index 200fb28..3ee46b6 100644 --- a/fieldset_forms.py +++ b/fieldset_forms.py @@ -7,12 +7,16 @@ pass class FieldsetForm(Form): - """Extends BaseForm and adds fieldsets and the possibililty to use - as_div. Inspired by WTForm.""" + """ + Extends a standard form and adds fieldsets and the possibililty + to use as_div for the automatic rendering of form fields. Inspired + by WTForm. + """ def __init__(self, *args): """Initialize a FormsetField.""" super(FieldsetForm, self).__init__(*args) + # check if the user specified the wished layout of the form if hasattr(self, 'Meta') and hasattr(self.Meta, 'layout'): msg = "Meta.layout must be iterable" assert hasattr(self.Meta.layout, '__getitem__'), msg @@ -29,10 +33,12 @@ return safestring.mark_safe(output) def create_fieldset(self, field): - """Create a
around a number of field instances.""" - # field[0] is the name of the fieldset and - # field[1:] the fields it should include - # create the divs in each fieldset by calling create_divs + """ + Create a
around a number of field instances. + field[0] is the name of the fieldset and field[1:] the fields + it should include. + """ + # Create the divs in each fieldset by calling create_divs. return u'
%s%s
' % (field[0], self.create_divs(field[1:])) @@ -44,7 +50,9 @@ # create a field instance for the bound field field_instance = self.base_fields[field] except KeyError: - # msg on a separate line since the line got too long otherwise + # could not create the instance so throw an exception + # 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 diff --git a/forms.py b/forms.py index 9e7580e..6e91d84 100644 --- a/forms.py +++ b/forms.py @@ -4,7 +4,8 @@ from fieldset_forms import FieldsetForm 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. """ languages = (("Arabic", "Arabic"), @@ -72,7 +73,8 @@ required = False) class Meta: - """Class to handle the automatic insertion of fieldsets and divs. + """ + 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 @@ -598,7 +600,7 @@ "topics_enabled", "unsubscribe_policy"]] class Login(FieldsetForm): - """Form to let the user log in. + """Form fields to let the user log in. """ address = forms.EmailField( label = _('Email address'), @@ -615,6 +617,10 @@ ) class Meta: + """ + Class to define the name of the fieldsets and what should be + included in each. + """ layout = [["Login", "address", "password"],] class ListMassSubscription(FieldsetForm): @@ -626,4 +632,8 @@ ) class Meta: + """ + Class to define the name of the fieldsets and what should be + included in each. + """ layout = [["Mass subscription", "emails"],] diff --git a/mockdata.py b/mockdata.py index fc77faf..033dc10 100644 --- a/mockdata.py +++ b/mockdata.py @@ -1,26 +1,38 @@ # -*- coding: utf-8 -*- def check_http_method(fn): - """Decorator function to return a mock response if the requested method was - PUT or PATCH. + """ + Decorator function to return a mock response if the requested + method was PUT or PATCH. Will be removed once this functionality + is implemented in the REST server. """ def http_req(*kwargs): if 'method' in kwargs: + # If one of the not implemented methods gets called, return + # a response saying everything went well (200). if method.upper() == 'PUT': return 200 elif method.upper() == 'PATCH': return 200 else: + # otherwise we return the function to let it perform its + # usual job return fn(*kwargs) - return http_req def add_mock_data(cls): - """Decorator function to add mock data from the database to a list. + """ + Decorator function to add mock data from the database to a list. + Once the functionality exists in the REST server this function can + be removed. """ cls.__orig__init__ = cls.__init__ def __init__(self, *args, **kwargs): + """ + Initiate the list with the missing information and call the + usual init function to get the real data already available. + """ cls.__orig__init__(self, *args, **kwargs) self.info['id'] = 9 #self.info['list_name'] = 'List name lorem ipsum dolor sit' @@ -116,4 +128,3 @@ cls.__init__ = __init__ return cls - diff --git a/views.py b/views.py index cc4b56e..abd5dcf 100644 --- a/views.py +++ b/views.py @@ -9,10 +9,21 @@ from forms import * def login_required(fn): - """Function (decorator) letting the user log in. + """ + Function (decorator) making sure the user has to log in before + they can continue. + To use it, add @login_required above the function that requires a + user to be logged in. The function requiring login will + automatically be added as an argument in the call. """ def _login_decorator(*request, **kwargs): - """Inner decorator to login. + """ + Inner decorator to require a user to login. This inner + function gets access to the arguments of the function demanding + login to be processed. + The function checks that a valid user name and password has + been provided and when this is the case the user gets + redirected to the original function. """ # If the user is already logged in, let them continue directly. try: @@ -24,7 +35,7 @@ # Authenticate the user # This is just a mockup since the authenticate functionality in # the rest server is still missing. - # TODO Anna 2010-08-04: implement real authenticate when possible + # TODO: implement real authenticate when possible valid_users = {"james@example.com": "james", "katie@example.com": "katie", "kevin@example.com": "kevin"} @@ -33,6 +44,7 @@ if form.is_valid(): if request[0].POST["address"] in valid_users.keys(): if request[0].POST["password"] == valid_users[request[0].POST["address"]]: + # TODO: change this to a better id when possible request[0].session['member_id'] = request[0].POST["address"] # make sure to "reset" the method before continuing request[0].method = 'GET' @@ -40,12 +52,20 @@ message = "Your username and password didn't match." else: message = "" - return render_to_response(template, {'form': Login(), 'message': message}) + return render_to_response(template, {'form': Login(), + 'message': message}) return _login_decorator @login_required def list_new(request, template = 'mailman-django/lists/new.html'): - """Show or process form to add a new mailing list. + """ + 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 + be logged in to create a new list. """ if request.method == 'POST': form = ListNew(request.POST) @@ -58,16 +78,17 @@ parts = listname.split('@') domain = c.get_domain(parts[1]) - if domain.info == 404: # failed to get domain so try creating one + if domain.info == 404: # failed to get domain so try + # creating a new one try: domain = c.create_domain(parts[1]) except MailmanRESTClientError, e: - # I don't think this error can ever appear... -- Anna + # I don't think this error can ever appear. -- Anna return HttpResponse(e) try: response = domain.create_list(parts[0]) return render_to_response('mailman-django/lists/created.html', - {'fqdn_listname': response.info['fqdn_listname'] }) + {'fqdn_listname': response.info['fqdn_listname']}) except MailmanRESTClientError, e: return HttpResponse(e) @@ -96,7 +117,11 @@ def list_info(request, fqdn_listname = None, template = 'mailman-django/lists/info.html'): - """Display list info and/or subscribe or unsubscribe a user to a list. + """ + 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. """ try: c = MailmanRESTClient('localhost:8001') @@ -105,6 +130,8 @@ return HttpResponse(e) if request.method == 'POST': form = False + # The form enables both subscribe and unsubscribe. As a result + # we must find out which was the case. action = request.POST.get('name', '') if action == "subscribe": form = ListSubscribe(request.POST) @@ -116,19 +143,24 @@ if action == "subscribe": real_name = form.cleaned_data.get('real_name', '') try: + # the form was valid so try to subscribe the user response = the_list.subscribe(address=email, real_name=real_name) return HttpResponseRedirect(reverse('list_index')) except Exception, e: return HttpResponse(e) elif action == "unsubscribe": + # the form was valid so try to unsubscribe the user try: response = the_list.unsubscribe(address=email) - return render_to_response('mailman-django/lists/unsubscribed.html', + template = 'mailman-django/lists/unsubscribed.html' + return render_to_response(template, {'listname': fqdn_listname}) except Exception, e: return HttpResponse(e) else: + # the user tried to post an incorrect form so make sure we + # return the filled in values and let the user try again. if action == "subscribe": subscribe = ListSubscribe(request.POST) unsubscribe = ListUnsubscribe(initial = {'listname': fqdn_listname, @@ -138,13 +170,14 @@ 'name' : 'subscribe'}) unsubscribe = ListUnsubscribe(request.POST) else: + # the request was a GET request so set the two forms to empty + # forms subscribe = ListSubscribe(initial = {'listname': fqdn_listname, 'name' : 'subscribe'}) unsubscribe = ListUnsubscribe(initial = {'listname': fqdn_listname, 'name' : 'unsubscribe'}) listinfo = c.get_list(fqdn_listname) - return render_to_response(template, {'subscribe': subscribe, 'unsubscribe': unsubscribe, 'fqdn_listname': fqdn_listname, @@ -152,8 +185,10 @@ def list_delete(request, fqdn_listname = None, template = 'mailman-django/lists/index.html'): - """Delete a list. """ + Delete a list by providing the full list name including domain. + """ + # create a connection to Mailman and get the list try: c = MailmanRESTClient('localhost:8001') @@ -175,7 +210,11 @@ @login_required def list_settings(request, fqdn_listname = None, template = 'mailman-django/lists/settings.html'): - """The settings of a list.""" + """ + View and edit the settings of a list. + The function requires the user to be logged in and have the + permissions necessary to perform the action. + """ message = "" try: c = MailmanRESTClient('localhost:8001') @@ -196,7 +235,11 @@ @login_required def mass_subscribe(request, fqdn_listname = None, template = 'mailman-django/lists/mass_subscribe.html'): - """Mass subscribe users to a list.""" + """ + Mass subscribe users to a list. + This functions is part of the settings for a list and requires the + user to be logged in to perform the action. + """ message = "" try: c = MailmanRESTClient('localhost:8001') @@ -207,6 +250,8 @@ form = ListMassSubscription(request.POST) if form.is_valid(): try: + # The emails to subscribe should each be provided on a + # separate line so get each of them. emails = request.POST["emails"].splitlines() message = "The mass subscription was successful." for email in emails: @@ -215,17 +260,26 @@ if len(parts) == 2 and '.' in parts[1]: the_list.subscribe(address=email, real_name="") else: + # At least one email address wasn't valid so + # overwrite the success message and ask them to + # try again. message = "Please enter valid email addresses." except Exception, e: return HttpResponse(e) else: + # A request to view the page was send so return the form to + # mass subscribe users. form = ListMassSubscription() return render_to_response(template, {'form': form, 'message': message, 'fqdn_listname': the_list.info['fqdn_listname']}) def logout(request): - """Let the user logout. + """ + Let the user logout. + Some functions requires the user to be logged in to perform the + actions. After the user is done, logging out is possible to avoid + others having rights they should not have. """ try: del request.session['member_id']