diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..54b312e --- /dev/null +++ b/.bzrignore @@ -0,0 +1 @@ +mailman_rest_client.py diff --git a/fieldset_forms.py b/fieldset_forms.py new file mode 100644 index 0000000..b02a541 --- /dev/null +++ b/fieldset_forms.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +from django.forms import Form +from django.utils import safestring +from django.forms.forms import BoundField + +class FieldsetForm(Form): + """Extends BaseForm and adds fieldsets and the possibililty to use + as_div. Inspired by WTForm.""" + + def __init__(self, *args): + """Initialize a FormsetField.""" + super(FieldsetForm, self).__init__(*args) + if hasattr(self, 'Meta') and hasattr(self.Meta, 'layout'): + assert hasattr(self.Meta.layout, '__getitem__'), "Meta.layout must be iterable" + self.layout = self.Meta.layout + else: + self.layout = self.fields.keys() + + def as_div(self): + """Render the form as a set of
s.""" + output = "" + # first, create the fieldsets + for index in range(len(self.layout)): + output += self.create_fieldset(self.layout[index]) + return safestring.mark_safe(output) + + def create_fieldset(self, field): + """Create a
around a number of field instances.""" + # create the divs in each fieldset by calling create_divs + return u'
%s%s
' % (field[0], + self.create_divs(field[1:])) + + def create_divs(self, fields): + """Create a
for each field.""" + output = "" + for field in fields: + try: + # create a field instance for the bound field + field_instance = self.base_fields[field] + except KeyError: + print "Could not resolve form field '%s'." % field + # create a bound field containing all the necessary fields + # from the model + 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)} + return output diff --git a/forms.py b/forms.py index 8e07cef..0a1a5bd 100644 --- a/forms.py +++ b/forms.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from django import forms from django.utils.translation import gettext as _ +from fieldset_forms import FieldsetForm -class ListNew(forms.Form): - """Form fields to add a new list. - languages are hard coded which should be replaced by a REST lookup of available languages. +class ListNew(FieldsetForm): + """Form fields to add a new list. Languages are hard coded which should + be replaced by a REST lookup of available languages. """ listname = forms.EmailField( label = _('List Name'), @@ -76,9 +77,17 @@ ), required = False ) + 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 + the fields that should be included in the fieldset. + """ + layout = [["List Details", "listname", "list_owner", "list_type"], + ["Available Languages", "languages"],] class ListSubscribe(forms.Form): - """Form fields to join an existing list """ listname = forms.EmailField( @@ -132,5 +141,4 @@ #initial = 'unsubscribe' ) - - # should at one point add the password to be required as well! \ No newline at end of file + # should at one point add the password to be required as well! diff --git a/mailman_rest_client.py b/mailman_rest_client.py deleted file mode 100644 index 377c45a..0000000 --- a/mailman_rest_client.py +++ /dev/null @@ -1,228 +0,0 @@ -# -*- coding: utf-8 -*- -import json -from httplib import HTTPConnection, HTTPException -from urllib import urlencode - -class MailmanRESTClientError(Exception): - """An exception thrown by the Mailman REST API client.""" - pass - -class MailmanRESTClient(object): - """A thin client wrapper for the Mailman REST API.""" - - def __init__(self, host): - self.host = host - if self.host[-1] == '/': - self.host = self.host[:-1] - - # general header information - self.headers = { - "User-Agent": "MailmanRESTClient", - "Accept": "text/plain", - } - - try: - self.c = HTTPConnection(self.host) - except: - raise MailmanRESTClientError('Could not connect to server') - - def __repr__(self): - return '' % self.host - - def _get_url(self, path): - try: - self.c.request('GET', path, None, self.headers) - except: - raise MailmanRESTClientError('Error sending request') - - try: - r = self.c.getresponse() - raw_data = r.read() - if len(raw_data) == 0: - raise None - data = json.loads(raw_data) - except: - raise MailmanRESTClientError('Error sending request') - finally: - self.c.close() - - return data - - def _post_url(self, path, data): - self.headers['Content-type'] = "application/x-www-form-urlencoded" - try: - self.c.request('POST', path, urlencode(data), self.headers) - except: - raise MailmanRESTClientError('Could not send request') - - try: - r = self.c.getresponse() - if r.status == 201: - return True - else: - return r.status - finally: - self.c.close() - - def _delete_url(self, path): - try: - self.c.request('DELETE', path, None, self.headers) - except: - raise MailmanRESTClientError('Could not send request') - - def _put_url(self, path): - pass - - def get_lists(self): - """Get a list of mail lists. - - returns a list of dicts - """ - try: - r = self._get_url('/3.0/lists') - except: - raise MailmanRESTClientError('Could not send request') - - if 'entries' not in r: - raise MailmanRESTClientError('No mailing lists found') - - return r['entries'] - - def read_list(self, list_name): - """Get information about list. - - :param list_name: name of the list to get information about - :type list_name: string - :rtype: dict - """ - try: - r = self._get_url('/3.0/lists/' + list_name) - except: - raise MailmanRESTClientError('Unable to get info about list') - - return r - - def create_list(self, fqdn_listname, **kwargs): - """Create a new list. - - :param fqdn_listname: the name of the list including the @ and the domain name. eg. test@example.com - :type fqdn_listname: string - :rtype: None - """ - data = { - 'fqdn_listname': fqdn_listname - } - data.update(**kwargs) - try: - return self._post_url('/3.0/lists', data) - except MailmanRESTClientError, e: - raise MailmanRESTClientError(e) - - - def subscribe_list(self, fqdn_listname, address, real_name, **kwargs): - """Add an address to a list. - - :param fqdn_listname: the name of the list . - :type fqdn_listname: string - :param address: email address to add to the list. - :type address: string - :param real_name: the "real" name for the address to be addded - :type real_name: string - """ - - data = { - 'fqdn_listname': fqdn_listname, - 'address': address, - 'real_name': real_name - } - data.update(**kwargs) - try: - r = self._post_url('/3.0/members', data) - except: - raise MailmanRESTClientError('unable to join list') - - return r - - def leave_list(self, fqdn_listname, address): - """Remove an address from a list. - - :param fqdn_listname: the name of the list. - :type fqdn_listname: string - :param address: email address that is leaving the list - :type address: string - :rtype: None - """ - try: - r = self._delete_url('/3.0/lists/' + fqdn_listname + '/member/' + address ) - except: - raise MailmanRESTClientError('unable to leave list') - - return True - - def get_members(self, fqdn_listname = None): - """Get a list of all members for all lists. - - :rtype: list of dicts - :type fqdn_listname: string - """ - - if fqdn_listname != None: - url = '/3.0/lists/' + fqdn_listname + '/members' - else: - url = '/3.0/members' - try: - r = self._get_url(url) - except: - raise MailmanRESTClientError('Could not complete request') - - if 'entries' not in r: - raise MailmanRESTClientError('Could not find any members') - - return r['entries'] - - def get_domains(self): - """Get a list of domains. - - :rtype: list of dicts - """ - try: - r = self._get_url('/3.0/domains') - except: - raise MailmanRESTClientError('Could not complete request') - if 'entries' not in r: - raise MailmanRESTClientError('Could not find any domains') - - return r['entries'] - - def read_domain(self, domain_name): - """Get information about a specific domain. - - :param domain_name: the name of the domain. - :rtype: dict - """ - - try: - r = self._get_url('/3.0/domains/' + domain_name) - except: - raise MailmanRESTClientError('Unable to read domain') - - return r - - def create_domain(self, email_host, **kwargs): - """Create a new domain name. - - :param email_host: domain name to create - :type email_host: string - :rtype: None - """ - data = { - 'email_host': email_host, - } - data.update(**kwargs) - try: - r = self._post_url('/3.0/domains', data) - except: - raise MailmanRESTClientError('Unable to create domain') - - return r - diff --git a/templates/mailman-django/lists/new.html b/templates/mailman-django/lists/new.html index e6cf7f5..4061e54 100644 --- a/templates/mailman-django/lists/new.html +++ b/templates/mailman-django/lists/new.html @@ -7,53 +7,11 @@
-
+ {{ form.as_div }} - {% trans "List Details" %} - -
- {{ form.listname.label_tag }} - {{ form.listname }} - {{ form.listname.errors }} -
- -
- {{ form.list_owner.label_tag }} - {{ form.list_owner}} - {{ form.list_owner.errors }} -
- -
- {{ form.list_type.label_tag }} - {{ form.list_type}} - {{ form.list_type.errors }} -
- -
- -
- - {% trans "Available Languages" %} - -

- This list of languages is just an example of an optional part of the form which is hidden by default (by giving its html fieldset a class attribute of "optional"). -

- -

- Information that isn't mandatory at creation should be hidden so it doesn't distract the user's attention. -

- -
- {{ form.label_tag }} - {{ form.languages }} - {{ form.languages.errors }} -
- -
- -
- -
+
+ +
{% endblock %} diff --git a/views.py b/views.py index 57156c7..a1ee10d 100644 --- a/views.py +++ b/views.py @@ -23,15 +23,16 @@ parts = listname.split('@') try: - r = c.read_domain(parts[1]) - except MailmanRESTClientError, e: + domain = c.get_domain(parts[1]) + except ValueError, e: try: c.create_domain(parts[1]) - except MailmanRESTClientError, e: + except MailmanRESTClientError, e: + # I don't think this error can ever appear but I couldn't + # trigger the one that might appear -- Anna return HttpResponse(e) - try: - response = c.create_list(fqdn_listname=listname) + response = domain.create_list(parts[0]) return HttpResponseRedirect(reverse('list_index')) except MailmanRESTClientError, e: return HttpResponse(e) @@ -65,6 +66,7 @@ """ try: c = MailmanRESTClient('localhost:8001') + the_list = c.get_list(fqdn_listname) except Exception, e: return HttpResponse(e) if request.method == 'POST': @@ -80,16 +82,14 @@ if action == "subscribe": real_name = form.cleaned_data.get('real_name', '') try: - response = c.subscribe_list(fqdn_listname=listname, - address=email, + response = the_list.subscribe(address=email, real_name=real_name) return HttpResponseRedirect(reverse('list_index')) except Exception, e: return HttpResponse(e) elif action == "unsubscribe": try: - response = c.leave_list(fqdn_listname=listname, - address=email) # doesn't throw error when not subscribed... + response = the_list.unsubscribe(address=email) return render_to_response('mailman-django/lists/unsubscribed.html', {'listname': fqdn_listname}) except Exception, e: @@ -109,7 +109,7 @@ unsubscribe = ListUnsubscribe(initial = {'listname': fqdn_listname, 'name' : 'unsubscribe'}) - listinfo = c.read_list(fqdn_listname) + listinfo = c.get_list(fqdn_listname) return render_to_response(template, {'subscribe': subscribe, 'unsubscribe': unsubscribe,