------------------------------------------------------------
revno: 6751
committer: Barry Warsaw <[email protected]>
branch nick: 3.0
timestamp: Mon 2009-07-20 23:13:59 -0400
message:
Our first writable REST API! You can now create new domains through the
webserver.
Fix the https/http urls.
Add the adapter for HTTPCharsets so POSTs work properly. Nice little cargo
cult from lazr.restful.
modified:
src/mailman/interfaces/domain.py
src/mailman/queue/docs/rest.txt
src/mailman/rest/adapters.py
src/mailman/rest/configuration.py
src/mailman/rest/configure.zcml
src/mailman/rest/docs/basic.txt
src/mailman/rest/docs/domains.txt
src/mailman/rest/docs/lists.txt
src/mailman/tests/test_documentation.py
=== modified file 'src/mailman/interfaces/domain.py'
--- src/mailman/interfaces/domain.py 2009-07-17 02:36:06 +0000
+++ src/mailman/interfaces/domain.py 2009-07-21 03:13:59 +0000
@@ -29,7 +29,7 @@
from lazr.restful.declarations import (
collection_default_content, export_as_webservice_collection,
- export_as_webservice_entry, exported)
+ export_as_webservice_entry, export_factory_operation, exported)
from zope.interface import Interface, Attribute
from zope.schema import TextLine
@@ -174,3 +174,27 @@
:return: The list of all known domains.
:rtype: list of `IDomain`
"""
+
+ @export_factory_operation(
+ IDomain,
+ ('email_host', 'description', 'base_url', 'contact_address'))
+ def new(email_host, description=None, base_url=None, contact_address=None):
+ """Add a new domain.
+
+ :param email_host: The email host name for the domain.
+ :type email_host: string
+ :param description: The description of the domain.
+ :type description: string
+ :param base_url: The base url, including the scheme for the web
+ interface of the domain. If not given, it defaults to
+ http://`email_host`/
+ :type base_url: string
+ :param contact_address: The email contact address for the human
+ managing the domain. If not given, defaults to
+ postmas...@`email_host`
+ :type contact_address: string
+ :return: The new domain object
+ :rtype: `IDomain`
+ :raises `BadDomainSpecificationError`: when the `email_host` is
+ already registered.
+ """
=== modified file 'src/mailman/queue/docs/rest.txt'
--- src/mailman/queue/docs/rest.txt 2009-05-10 20:13:02 +0000
+++ src/mailman/queue/docs/rest.txt 2009-07-21 03:13:59 +0000
@@ -1,3 +1,4 @@
+===========
REST server
===========
@@ -13,11 +14,11 @@
http_etag: "..."
mailman_version: GNU Mailman 3.0... (...)
python_version: ...
- resource_type_link: https://localhost:8001/3.0/#system
- self_link: https://localhost:8001/3.0/system
+ resource_type_link: http://localhost:8001/3.0/#system
+ self_link: http://localhost:8001/3.0/system
Clean up
---------
+========
>>> master.stop()
=== modified file 'src/mailman/rest/adapters.py'
--- src/mailman/rest/adapters.py 2009-07-17 02:36:06 +0000
+++ src/mailman/rest/adapters.py 2009-07-21 03:13:59 +0000
@@ -61,3 +61,10 @@
if domain is None:
raise NotFound(self, name)
return domain
+
+ def new(self, email_host, description=None, base_url=None,
+ contact_address=None):
+ """See `IDomainCollection`."""
+ value = self._manager.add(
+ email_host, description, base_url, contact_address)
+ return value
=== modified file 'src/mailman/rest/configuration.py'
--- src/mailman/rest/configuration.py 2009-07-01 22:04:04 +0000
+++ src/mailman/rest/configuration.py 2009-07-21 03:13:59 +0000
@@ -25,6 +25,7 @@
]
+from lazr.config import as_boolean
from lazr.restful.interfaces import IWebServiceConfiguration
from zope.interface import implements
@@ -51,7 +52,7 @@
@property
def use_https(self):
"""See `IWebServiceConfiguration`."""
- return config.webservice.use_https
+ return as_boolean(config.webservice.use_https)
# This should match the major.minor Mailman version.
service_version_uri_prefix = '{0.MAJOR_REV}.{0.MINOR_REV}'.format(version)
=== modified file 'src/mailman/rest/configure.zcml'
--- src/mailman/rest/configure.zcml 2009-07-17 02:36:06 +0000
+++ src/mailman/rest/configure.zcml 2009-07-21 03:13:59 +0000
@@ -12,6 +12,8 @@
<webservice:register module="mailman.interfaces.listmanager" />
<webservice:register module="mailman.interfaces.system" />
+ <adapter factory="zope.publisher.http.HTTPCharsets" />
+
<adapter
for="mailman.interfaces.domain.IDomainManager"
provides="mailman.interfaces.domain.IDomainCollection"
=== modified file 'src/mailman/rest/docs/basic.txt'
--- src/mailman/rest/docs/basic.txt 2009-05-27 21:56:01 +0000
+++ src/mailman/rest/docs/basic.txt 2009-07-21 03:13:59 +0000
@@ -16,8 +16,8 @@
http_etag: "..."
mailman_version: GNU Mailman 3.0... (...)
python_version: ...
- resource_type_link: https://localhost:8001/3.0/#system
- self_link: https://localhost:8001/3.0/system
+ resource_type_link: http://localhost:8001/3.0/#system
+ self_link: http://localhost:8001/3.0/system
Non-existent links
=== modified file 'src/mailman/rest/docs/domains.txt'
--- src/mailman/rest/docs/domains.txt 2009-07-19 02:31:45 +0000
+++ src/mailman/rest/docs/domains.txt 2009-07-21 03:13:59 +0000
@@ -14,7 +14,7 @@
initially none.
>>> dump_json('http://localhost:8001/3.0/domains')
- resource_type_link: https://localhost:8001/3.0/#domains
+ resource_type_link: http://localhost:8001/3.0/#domains
start: None
total_size: 0
@@ -34,10 +34,10 @@
description: An example domain
email_host: example.com
http_etag: "..."
- resource_type_link: https://localhost:8001/3.0/#domain
- self_link: https://localhost:8001/3.0/domains/example.com
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/example.com
url_host: lists.example.com
- resource_type_link: https://localhost:8001/3.0/#domains
+ resource_type_link: http://localhost:8001/3.0/#domains
start: 0
total_size: 1
@@ -64,8 +64,8 @@
description: An example domain
email_host: example.com
http_etag: "..."
- resource_type_link: https://localhost:8001/3.0/#domain
- self_link: https://localhost:8001/3.0/domains/example.com
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/example.com
url_host: lists.example.com
entry 1:
base_url: http://mail.example.org
@@ -73,8 +73,8 @@
description: None
email_host: example.org
http_etag: "..."
- resource_type_link: https://localhost:8001/3.0/#domain
- self_link: https://localhost:8001/3.0/domains/example.org
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/example.org
url_host: mail.example.org
entry 2:
base_url: http://example.net
@@ -82,10 +82,10 @@
description: Porkmasters
email_host: lists.example.net
http_etag: "..."
- resource_type_link: https://localhost:8001/3.0/#domain
- self_link: https://localhost:8001/3.0/domains/lists.example.net
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/lists.example.net
url_host: example.net
- resource_type_link: https://localhost:8001/3.0/#domains
+ resource_type_link: http://localhost:8001/3.0/#domains
start: 0
total_size: 3
@@ -102,8 +102,8 @@
description: Porkmasters
email_host: lists.example.net
http_etag: "..."
- resource_type_link: https://localhost:8001/3.0/#domain
- self_link: https://localhost:8001/3.0/domains/lists.example.net
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/lists.example.net
url_host: example.net
But we get a 404 for a non-existent domain.
@@ -112,3 +112,43 @@
Traceback (most recent call last):
...
HTTPError: HTTP Error 404: Not Found
+
+
+Creating new domains
+====================
+
+New domains can be created by posting to the 'domains' url. However
+lazr.restful requires us to use a 'named operation' instead of posting
+directly to the URL.
+
+ >>> dump_json('http://localhost:8001/3.0/domains', {
+ ... 'ws.op': 'new',
+ ... 'email_host': 'lists.example.com',
+ ... })
+ URL: http://localhost:8001/3.0/domains
+ content-length: 0
+ content-type: text/plain
+ date: ...
+ location: http://localhost:8001/3.0/domains/lists.example.com
+ server: WSGIServer/... Python/...
+ x-content-type-warning: guessed from content
+ x-powered-by: Zope (www.zope.org), Python (www.python.org)
+
+Now the web service knows about our new domain.
+
+ >>> dump_json('http://localhost:8001/3.0/domains/lists.example.com')
+ base_url: http://lists.example.com
+ contact_address: [email protected]
+ description: None
+ email_host: lists.example.com
+ http_etag: "349365fdbf946e64fc1052b936b9192eaa94b850"
+ resource_type_link: http://localhost:8001/3.0/#domain
+ self_link: http://localhost:8001/3.0/domains/lists.example.com
+ url_host: lists.example.com
+
+And the new domain is in our database.
+
+ >>> manager['lists.example.com']
+ <Domain lists.example.com,
+ base_url: http://lists.example.com,
+ contact_address: [email protected]>
=== modified file 'src/mailman/rest/docs/lists.txt'
--- src/mailman/rest/docs/lists.txt 2009-07-11 01:55:26 +0000
+++ src/mailman/rest/docs/lists.txt 2009-07-21 03:13:59 +0000
@@ -7,6 +7,6 @@
yet though.
>>> dump_json('http://localhost:8001/3.0/lists')
- resource_type_link: https://localhost:8001/3.0/#mailing_lists
+ resource_type_link: http://localhost:8001/3.0/#mailing_lists
start: None
total_size: 0
=== modified file 'src/mailman/tests/test_documentation.py'
--- src/mailman/tests/test_documentation.py 2009-07-19 02:31:45 +0000
+++ src/mailman/tests/test_documentation.py 2009-07-21 03:13:59 +0000
@@ -37,6 +37,7 @@
import unittest
from email import message_from_string
+from urllib import urlencode
from urllib2 import urlopen
import mailman
@@ -109,16 +110,28 @@
print '{0:{2}}: {1}'.format(key, msgdata[key], longest)
-def dump_json(url):
+def dump_json(url, data=None):
"""Print the JSON dictionary read from a URL.
:param url: The url to open, read, and print.
:type url: string
+ :param data: Data to use to POST to a URL.
+ :type data: dict
"""
- fp = urlopen(url)
+ if data is None:
+ fp = urlopen(url)
+ else:
+ fp = urlopen(url, urlencode(data))
# fp does not support the context manager protocol.
try:
- data = json.load(fp)
+ raw_data = fp.read()
+ if len(raw_data) == 0:
+ print 'URL:', fp.geturl()
+ info = fp.info()
+ for header in sorted(info):
+ print '{0}: {1}'.format(header, info[header])
+ return
+ data = json.loads(raw_data)
finally:
fp.close()
for key in sorted(data):
--
lp:mailman
https://code.launchpad.net/~mailman-coders/mailman/3.0
Your team Mailman Checkins is subscribed to branch lp:mailman.
To unsubscribe from this branch go to
https://code.launchpad.net/~mailman-coders/mailman/3.0/+edit-subscription.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org