diff --git a/mailman_rest_client.py b/mailman_rest_client.py index 91178b8..10c940b 100644 --- a/mailman_rest_client.py +++ b/mailman_rest_client.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (C) 2010 by the Free Software Foundation, Inc. # # This file is part of GNU Mailman. @@ -32,7 +31,6 @@ import json from httplib2 import Http -from mailman_django import mockdata from operator import itemgetter from urllib import urlencode from urllib2 import HTTPError @@ -64,13 +62,12 @@ def __repr__(self): return '' % self.host - @mockdata.check_http_method - def _http_request(self, path, data=None, method=None, **kwargs): + def _http_request(self, path, data=None, method=None): """Send an HTTP request. :param path: the path to send the request to :type path: string - :param data: POST, PUT or PATCH data to send + :param data: POST oder PUT data to send :type data: dict :param method: the HTTP method; defaults to GET or POST (if data is not None) @@ -86,15 +83,14 @@ 'Accept': 'text/plain', } if data is not None: - data = urlencode(data) + data = urlencode(data, doseq=True) + headers['Content-type'] = "application/x-www-form-urlencoded" if method is None: if data is None: method = 'GET' else: method = 'POST' method = method.upper() - if method == 'POST': - headers['Content-type'] = "application/x-www-form-urlencoded" response, content = Http().request(url, method, data, headers) if method == 'GET': if response.status // 100 != 2: @@ -167,29 +163,6 @@ return sorted(response['entries'], key=itemgetter('self_link')) - def get_member(self, email_address, fqdn_listname): - """Return a member object. - - :param email_adresses: the email address used - :type email_address: string - :param fqdn_listname: the mailing list - :type fqdn_listname: string - :return: a member object - :rtype: _Member - """ - return _Member(self.host, email_address, fqdn_listname) - - - def get_user(self, email_address): - """Find and return a user object. - - :param email_address: one of the user's email addresses - :type email: string: - :returns: a user object - :rtype: _User - """ - return _User(self.host, email_address) - class _Domain(MailmanRESTClient): """A domain wrapper for the MailmanRESTClient.""" @@ -224,7 +197,7 @@ fqdn_listname = list_name + '@' + self.info['email_host'] return self._http_request('/3.0/lists/' + fqdn_listname, None, 'DELETE') -@mockdata.add_list_mock_data + class _List(MailmanRESTClient): """A mailing list wrapper for the MailmanRESTClient.""" @@ -239,6 +212,7 @@ """ super(_List, self).__init__(host) self.info = self._http_request('/3.0/lists/' + fqdn_listname) + self.config = self._http_request('/3.0/lists/%s/config' % fqdn_listname) def subscribe(self, address, real_name=None): """Add an address to a list. @@ -284,137 +258,18 @@ else: return sorted(response['entries'], key=itemgetter('self_link')) + + def update_config(self, data): + """Update the list configuration. - def get_member(self, email_address): - """Return a member object. - - :param email_adresses: the email address used - :type email_address: string - :param fqdn_listname: the mailing list - :type fqdn_listname: string - :return: a member object - :rtype: _Member + :param data: A dict with the config attributes to be updated. + :type data: dict + :return: the return code of the http request + :rtype: integer """ - return _Member(self.host, email_address, self.info['fqdn_listname']) - - def update_list(self, data): - """Update the settings for a list. - """ - return self._http_request('/3.0/lists/' + self.info['fqdn_listname'], - data, method='PATCH') - - def __str__(self): - """A string representation of a list. - """ - return "A list object for the list '%s'." % self.info['fqdn_listname'] - - -@mockdata.add_user_mock_data -class _User(MailmanRESTClient): - """A user wrapper for the MailmanRESTClient.""" - - def __init__(self, host, email_address): - """Connect to host and get user information. - - :param host: the host name of the REST API - :type host: string - :param email_address: email address - :type email_address: string - :return: a user object - :rtype: _User - """ - super(_User, self).__init__(host) - # store the email address the instance was created with - self.email_address = email_address - # create an info attribute - self.info = {} - - def get_email_addresses(self): - """Return a list of all email adresses used by this user. - - :return: a list of email addresses - :rtype: list - """ - response = self._http_request('/3.0/users/' + self.email_address + '/email_adresses') - if type(response) is int: - return response - elif 'entries' not in response: - return [] - else: - return sorted(response['entries']) - - def get_lists(self): - """Return a list of all mailing list connected to a user. - - :return: a list of dicts with all mailing lists - :rtype: list - """ - path = '/3.0/users/%s/lists' % self.email_address - response = self._http_request(path) - if type(response) is int: - return response - elif 'entries' not in response: - return [] - else: - # Return a dict with entries sorted by fqdn_listname - return sorted(response['entries'], - key=itemgetter('fqdn_listname')) - - def update(self, data=None): - """Update user settings.""" - - # If data is None, use the info dict - if data is None: - data = self.info - - path = '/3.0/users/%s' % (self.email_address) - return self._http_request(path, data, method='PATCH') - - def __str__(self): - """A string representation of a member.""" - - return "A user object for the user '%s'." % self.info['real_name'] - - -@mockdata.add_member_mock_data -class _Member(MailmanRESTClient): - """A user wrapper for the MailmanRESTClient.""" - - def __init__(self, host, email_address, fqdn_listname): - """Connect to host and get membership information. - - :param host: the host name of the REST API - :type host: string - :param email_address: email address - :type email_address: string - :param fqdn_listname: the mailing list - :type fqdn_listname: string - :return: a member object - :rtype: _Member - """ - super(_Member, self).__init__(host) - # Create an info attribute to receive member info via the API. - # To be filled with actual data as soon as the API supports it. - self.info = {} - # Keep these values out of the info dict so info can be send - # back to the server without additional keys - self.email_address = email_address - self.fqdn_listname = fqdn_listname - - def update(self, data=None): - """Update member settings.""" - - # If data is None, use the info dict - if data is None: - data = self.info - - path = '/3.0/lists/%s/member/%s' % (self.fqdn_listname, - self.email_address) - return self._http_request(path, data, method='PATCH') - - def __str__(self): - """A string representation of a member.""" - - return "A member object for '%s', subscribed to '%s'." \ - % (self.email_address, self.fqdn_listname) - + url = '/3.0/lists/%s/config' % self.info['fqdn_listname'] + status = self._http_request(url, data, 'PATCH') + if status == 200: + for key in data: + self.config[key] = data[key] + return status diff --git a/restclient.txt b/restclient.txt index 75711a9..3b2de34 100644 --- a/restclient.txt +++ b/restclient.txt @@ -48,7 +48,7 @@ Mailing lists ============= -Now let's add a mailing list called 'test-one'. +Now let's add s mailing list called 'test-one'. >>> new_list = my_domain.create_list('test-one') @@ -56,27 +56,62 @@ >>> another_list = my_domain.create_list('test-two') >>> pprint(another_list.info) - {'advertised': True, - ... - 'welcome_msg': 'Welcome message lorem ipsum dolor sit'} + {u'fqdn_listname': u'test-two@example.com', + u'host_name': u'example.com', + u'http_etag': u'"a05542c9faa07cbe2b8fdf8a1655a2361ab365f2"', + u'list_name': u'test-two', + u'real_name': u'Test-two', + u'self_link': u'http://localhost:8001/3.0/lists/test-two@example.com'} Later the new list can be instantiated using get_list(): >>> some_list = client.get_list('test-one@example.com') +Also a ``config`` dictionary is populated with some default list configuration options + + >>> pprint(some_list.config) + {u'acceptable_aliases': [], + ... + u'description': u'', + ... + u'real_name': u'Test-one', + ... + +You can change these options: + + >>> data = dict(real_name='Fnorg', + ... description='Discuss all things Fnorg') + >>> some_list.update_config(data) + 200 + >>> some_list.config['real_name'] + u'Fnorg' + >>> some_list.config['description'] + u'Discuss all things Fnorg' + +New instances of the list also show these changes: + + >>> some_list = client.get_list('test-one@example.com') + >>> pprint(some_list.config) + {u'acceptable_aliases': [], + ... + u'description': u'Discuss all things Fnorg', + ... + u'real_name': u'Fnorg', + ... + The lists have been added and get_lists() returns a list of dicts, sorted by fqdn_listname. >>> pprint(client.get_lists()) [{u'fqdn_listname': u'test-one@example.com', u'host_name': u'example.com', - u'http_etag': u'"5e99519ef1b823a52254b77e89bec54fbd17bef0"', + ... u'list_name': u'test-one', - u'real_name': u'Test-one', + u'real_name': u'Fnorg', u'self_link': u'http://localhost:8001/3.0/lists/test-one@example.com'}, {u'fqdn_listname': u'test-two@example.com', u'host_name': u'example.com', - u'http_etag': u'"a05542c9faa07cbe2b8fdf8a1655a2361ab365f2"', + ... u'list_name': u'test-two', u'real_name': u'Test-two', u'self_link': u'http://localhost:8001/3.0/lists/test-two@example.com'}] @@ -119,84 +154,8 @@ >>> new_list.unsubscribe('meg@example.com') 200 +You can delete lists via their domain: -Users -===== - -Users and their settings can be accessed by using one of their email -addresses. - - >>> jack = client.get_user('jack@example.com') - >>> print jack - A user object for the user 'Jack'. - >>> pprint(jack.info) - {u'real_name': u'Jack'} - -To update the User settings, change the info attribute and call update(). - - >>> jack.info['real_name'] = 'Jack, Brother of Meg' - >>> jack.update() + >>> my_domain.delete_list('test-two') 204 -You can get a list of all lists a user has subscribed and/or is an owner -or moderator of by using .get_lists(). - - >>> pprint(jack.get_lists()) - [{u'email_address': u'jack@example.com', - u'fqdn_listname': u'test-one@example.com', - u'real_name': u'Test-one'}, - {u'email_address': u'jack@example.com', - u'fqdn_listname': u'test-two@example.com', - u'real_name': u'Test-two'}] - -To see which email addresses jack has used to subscribe to the lists on -that domain, use get_email_addresses(). - - >>> pprint(jack.get_email_addresses()) - [u'jack@example.com'] - - -Membership -========== - -To know more about the membership details of Jack's subscription, you -need an instance of a member. There are two ways to get a member object: -Either get it from the client object... - - >>> member = client.get_member('jack@example.com', 'test-one@example.com') - -...or from a list object, providing only an email address as a parameter: - - >>> member = new_list.get_member('jack@example.com') - >>> print member - A member object for 'jack@example.com', subscribed to 'test-one@example.com'. - >>> member_info = member.info - >>> pprint(member_info) - {'_original': 'Original lorem ipsum dolor sit', - 'acknowledge_posts': True, - 'address': 'Address lorem ipsum dolor sit', - 'address_id': 9, - 'delivery_mode': 'Delivery mode lorem ipsum dolor sit', - 'delivery_status': 'Delivery status lorem ipsum dolor sit', - 'hide_address': True, - 'id': 9, - 'is_moderated': True, - 'mailing_list': 'Mailing list lorem ipsum dolor sit', - 'password': 'Password lorem ipsum dolor sit', - 'preferences_id': 9, - 'preferred_language': 'Preferred language lorem ipsum dolor sit', - 'real_name': 'Real name lorem ipsum dolor sit', - 'receive_list_copy': True, - 'receive_own_postings': True, - 'registered_on': '2000-01-01 00:00:00', - 'role': 'Role lorem ipsum dolor sit', - 'user_id': 9, - 'verified_on': '2000-01-01 00:00:00'} - -To change any of the membership settings just set the relevant values and use update_member(). - - >>> member.info['password'] = 'someencryptednewpasswordstring' - >>> member.update() - 204 - -