summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2010-02-23 14:31:41 -0500
committerBarry Warsaw2010-02-23 14:31:41 -0500
commit0fa9260a3d23b7ba17de727e66bcc27a0aeacc29 (patch)
treebc45a5ba133e22eac478196436f9e5360c74ebfe /src
parent6ebd29504f204913a1c57f64d802151fc97bfb41 (diff)
downloadmailman-0fa9260a3d23b7ba17de727e66bcc27a0aeacc29.tar.gz
mailman-0fa9260a3d23b7ba17de727e66bcc27a0aeacc29.tar.zst
mailman-0fa9260a3d23b7ba17de727e66bcc27a0aeacc29.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/bin/qrunner.py5
-rw-r--r--src/mailman/config/configure.zcml4
-rw-r--r--src/mailman/core/system.py3
-rw-r--r--src/mailman/interfaces/address.py2
-rw-r--r--src/mailman/interfaces/domain.py83
-rw-r--r--src/mailman/interfaces/listmanager.py9
-rw-r--r--src/mailman/interfaces/mailinglist.py32
-rw-r--r--src/mailman/interfaces/member.py7
-rw-r--r--src/mailman/interfaces/membership.py19
-rw-r--r--src/mailman/interfaces/rest.py2
-rw-r--r--src/mailman/interfaces/system.py16
-rw-r--r--src/mailman/rest/docs/basic.txt3
-rw-r--r--src/mailman/rest/docs/domains.txt11
-rw-r--r--src/mailman/rest/webservice.py225
14 files changed, 201 insertions, 220 deletions
diff --git a/src/mailman/bin/qrunner.py b/src/mailman/bin/qrunner.py
index 7f5f321f5..d75eea4e5 100644
--- a/src/mailman/bin/qrunner.py
+++ b/src/mailman/bin/qrunner.py
@@ -28,6 +28,7 @@ __all__ = [
import sys
import signal
import logging
+import traceback
from mailman.config import config
from mailman.core.i18n import _
@@ -154,8 +155,8 @@ def make_qrunner(name, slice, range, once=False):
if config.options.options.subproc:
# Exit with SIGTERM exit code so the master watcher won't try to
# restart us.
- print >> sys.stderr, _('Cannot import runner module: $module_name')
- print >> sys.stderr, error
+ print >> sys.stderr, _('Cannot import runner module: $class_path')
+ traceback.print_exc()
sys.exit(signal.SIGTERM)
else:
raise
diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml
index 5e8de8527..5cfdf41fe 100644
--- a/src/mailman/config/configure.zcml
+++ b/src/mailman/config/configure.zcml
@@ -2,7 +2,9 @@
<configure
xmlns="http://namespaces.zope.org/zope">
- <include package="mailman.rest" file="configure.zcml"/>
+ <include package="zope.component" file="meta.zcml"/>
+
+ <!-- include package="mailman.rest" file="configure.zcml"/ -->
<adapter
for="mailman.interfaces.mailinglist.IMailingList"
diff --git a/src/mailman/core/system.py b/src/mailman/core/system.py
index b848fbdb7..6048fa187 100644
--- a/src/mailman/core/system.py
+++ b/src/mailman/core/system.py
@@ -28,7 +28,6 @@ __all__ = [
import sys
from zope.interface import implements
-from zope.location.interfaces import ILocation
from mailman import version
from mailman.interfaces.system import ISystem
@@ -36,7 +35,7 @@ from mailman.interfaces.system import ISystem
class System:
- implements(ISystem, ILocation)
+ implements(ISystem)
@property
def mailman_version(self):
diff --git a/src/mailman/interfaces/address.py b/src/mailman/interfaces/address.py
index 2b074ddab..d54ea64c3 100644
--- a/src/mailman/interfaces/address.py
+++ b/src/mailman/interfaces/address.py
@@ -30,7 +30,6 @@ __all__ = [
]
-from lazr.restful.declarations import error_status
from zope.interface import Interface, Attribute
from mailman.interfaces.errors import MailmanError
@@ -53,7 +52,6 @@ class AddressNotLinkedError(AddressError):
"""The address is not linked to the user."""
-@error_status(400)
class InvalidEmailAddressError(AddressError):
"""Email address is invalid."""
diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py
index 340cddd79..a8770b664 100644
--- a/src/mailman/interfaces/domain.py
+++ b/src/mailman/interfaces/domain.py
@@ -23,23 +23,17 @@ __metaclass__ = type
__all__ = [
'BadDomainSpecificationError',
'IDomain',
- 'IDomainCollection',
'IDomainManager',
]
-from lazr.restful.declarations import (
- collection_default_content, error_status, export_as_webservice_collection,
- export_as_webservice_entry, export_factory_operation, exported)
from zope.interface import Interface, Attribute
-from zope.schema import TextLine
from mailman.core.errors import MailmanError
from mailman.core.i18n import _
-@error_status(400)
class BadDomainSpecificationError(MailmanError):
"""The specification of a virtual domain is invalid or duplicated."""
@@ -48,37 +42,21 @@ class BadDomainSpecificationError(MailmanError):
class IDomain(Interface):
"""Interface representing domains."""
- export_as_webservice_entry()
+ email_host = Attribute('The host name for email for this domain.')
- email_host = exported(TextLine(
- title=_('Email host name'),
- description=_('The host name for email for this domain.'),
- ))
+ url_host = Attribute(
+ 'The host name for the web interface for this domain.')
- url_host = exported(TextLine(
- title=_('Web host name'),
- description=_('The host name for the web interface for this domain.')
- ))
+ base_url = Attribute("""\
+ The base url for the Mailman server at this domain, which includes the
+ scheme and host name.""")
- base_url = exported(TextLine(
- title=_('Base URL'),
- description=_("""\
- The base url for the Mailman server at this domain, which includes the
- scheme and host name."""),
- ))
+ description = Attribute(
+ 'The human readable description of the domain name.')
- description = exported(TextLine(
- title=_('Description'),
- description=_('The human readable description of the domain name.'),
- ))
-
- contact_address = exported(TextLine(
- title=_('Contact address'),
- description=_("""\
- The contact address for the human at this domain.
-
- E.g. postmaster@example.com"""),
- ))
+ contact_address = Attribute("""\
+ The contact address for the human at this domain.
+ E.g. postmaster@example.com""")
def confirm_url(token=''):
"""The url used for various forms of confirmation.
@@ -158,42 +136,3 @@ class IDomainManager(Interface):
:return: True if this domain is known.
:rtype: bool
"""
-
-
-
-class IDomainCollection(Interface):
- """The set of domains available via the REST API."""
-
- export_as_webservice_collection(IDomain)
-
- @collection_default_content()
- def get_domains():
- """The list of all domains.
-
- :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
- postmaster@`email_host`
- :type contact_address: string
- :return: The new domain object
- :rtype: `IDomain`
- :raises `BadDomainSpecificationError`: when the `email_host` is
- already registered.
- """
diff --git a/src/mailman/interfaces/listmanager.py b/src/mailman/interfaces/listmanager.py
index 5958d677a..f47fe658e 100644
--- a/src/mailman/interfaces/listmanager.py
+++ b/src/mailman/interfaces/listmanager.py
@@ -27,9 +27,6 @@ __all__ = [
]
-from lazr.restful.declarations import (
- collection_default_content, error_status, export_as_webservice_collection,
- export_factory_operation)
from zope.interface import Interface, Attribute
from mailman.interfaces.errors import MailmanError
@@ -37,7 +34,6 @@ from mailman.interfaces.mailinglist import IMailingList
-@error_status(400)
class ListAlreadyExistsError(MailmanError):
"""Attempted to create a mailing list that already exists.
@@ -46,7 +42,6 @@ class ListAlreadyExistsError(MailmanError):
"""
-@error_status(400)
class NoSuchListError(MailmanError):
"""Attempt to access a mailing list that does not exist."""
@@ -68,8 +63,6 @@ class IListManager(Interface):
`mylist@example.com`.
"""
- export_as_webservice_collection(IMailingList)
-
def create(fqdn_listname):
"""Create a mailing list with the given name.
@@ -104,7 +97,6 @@ class IListManager(Interface):
"""An iterator over the fully qualified list names of all mailing
lists managed by this list manager.""")
- @collection_default_content()
def get_mailing_lists():
"""The list of all mailing lists.
@@ -112,7 +104,6 @@ class IListManager(Interface):
:rtype: list of `IMailingList`
"""
- @export_factory_operation(IMailingList, ('fqdn_listname',))
def new(fqdn_listname):
"""Add a new maling list.
diff --git a/src/mailman/interfaces/mailinglist.py b/src/mailman/interfaces/mailinglist.py
index 0efe00625..2e2083e72 100644
--- a/src/mailman/interfaces/mailinglist.py
+++ b/src/mailman/interfaces/mailinglist.py
@@ -30,11 +30,8 @@ __all__ = [
]
-from lazr.restful.declarations import (
- export_as_webservice_entry, exported)
from munepy import Enum
from zope.interface import Interface, Attribute
-from zope.schema import TextLine
from mailman.core.i18n import _
@@ -71,53 +68,40 @@ class DigestFrequency(Enum):
class IMailingList(Interface):
"""A mailing list."""
- # Use a different singular and plural name for the resource type than
- # lazr.restful gives it as a default (which is normally taken from the
- # interface name).
- export_as_webservice_entry('list', 'lists')
-
# List identity
- list_name = exported(TextLine(
- title=_('Short name'),
- description=_("""\
+ list_name = Attribute("""\
The read-only short name of the mailing list. Note that where a
Mailman installation supports multiple domains, this short name may
not be unique. Use the fqdn_listname attribute for a guaranteed
unique id for the mailing list. This short name is always the local
part of the posting email address. For example, if messages are
posted to mylist@example.com, then the list_name is 'mylist'.
- """)))
- host_name = exported(TextLine(
- title=_('Host name'),
- description=_("""\
+ """)
+ host_name = Attribute("""\
The read-only domain name 'hosting' this mailing list. This is always
the domain name part of the posting email address, and it may bear no
relationship to the web url used to access this mailing list. For
example, if messages are posted to mylist@example.com, then the
host_name is 'example.com'.
- """)))
+ """)
- fqdn_listname = exported(TextLine(
- title=_('Fully qualified list name'),
- description=_("""\
+ fqdn_listname = Attribute("""\
The read-only fully qualified name of the mailing list. This is the
guaranteed unique id for the mailing list, and it is always the
address to which messages are posted, e.g. mylist@example.com. It is
always comprised of the list_name + '@' + host_name.
- """)))
+ """)
domain = Attribute(
"""The `IDomain` that this mailing list is defined in.""")
- real_name = exported(TextLine(
- title=_('Real name'),
- description=_("""\
+ real_name = Attribute("""\
The short human-readable descriptive name for the mailing list. By
default, this is the capitalized `list_name`, but it can be changed to
anything. This is used in locations such as the message footers and
Subject prefix.
- """)))
+ """)
list_id = Attribute(
"""The RFC 2919 List-ID header value.""")
diff --git a/src/mailman/interfaces/member.py b/src/mailman/interfaces/member.py
index 871957922..df5ccc935 100644
--- a/src/mailman/interfaces/member.py
+++ b/src/mailman/interfaces/member.py
@@ -32,8 +32,6 @@ __all__ = [
]
-from lazr.restful.declarations import (
- error_status, export_as_webservice_entry, exported)
from munepy import Enum
from zope.interface import Interface, Attribute
@@ -78,7 +76,6 @@ class MembershipError(MailmanError):
"""Base exception for all membership errors."""
-@error_status(400)
class AlreadySubscribedError(MembershipError):
"""The member is already subscribed to the mailing list with this role."""
@@ -93,7 +90,6 @@ class AlreadySubscribedError(MembershipError):
self._address, self._role, self._fqdn_listname)
-@error_status(400)
class MembershipIsBannedError(MembershipError):
"""The address is not allowed to subscribe to the mailing list."""
@@ -107,7 +103,6 @@ class MembershipIsBannedError(MembershipError):
self._address, self._mlist)
-@error_status(400)
class NotAMemberError(MembershipError):
"""The address is not a member of the mailing list."""
@@ -125,8 +120,6 @@ class NotAMemberError(MembershipError):
class IMember(Interface):
"""A member of a mailing list."""
- export_as_webservice_entry()
-
mailing_list = Attribute(
"""The mailing list subscribed to.""")
diff --git a/src/mailman/interfaces/membership.py b/src/mailman/interfaces/membership.py
index 6e6176e8f..bcef2eb09 100644
--- a/src/mailman/interfaces/membership.py
+++ b/src/mailman/interfaces/membership.py
@@ -25,11 +25,7 @@ __all__ = [
]
-from lazr.restful.declarations import (
- collection_default_content, export_as_webservice_collection,
- export_write_operation, operation_parameters)
from zope.interface import Interface
-from zope.schema import TextLine
from mailman.core.i18n import _
from mailman.interfaces.member import IMember
@@ -39,9 +35,6 @@ from mailman.interfaces.member import IMember
class ISubscriptionService(Interface):
"""Subscription services for the REST API."""
- export_as_webservice_collection(IMember)
-
- @collection_default_content()
def get_members():
"""Return a sequence of all members of all mailing lists.
@@ -55,13 +48,6 @@ class ISubscriptionService(Interface):
:rtype: list of `IMember`
"""
- @operation_parameters(
- fqdn_listname=TextLine(),
- address=TextLine(),
- real_name=TextLine(),
- delivery_mode=TextLine(),
- )
- @export_write_operation()
def join(fqdn_listname, address, real_name=None, delivery_mode=None):
"""Subscribe to a mailing list.
@@ -94,11 +80,6 @@ class ISubscriptionService(Interface):
:raises ValueError: when `delivery_mode` is invalid.
"""
- @operation_parameters(
- fqdn_listname=TextLine(),
- address=TextLine(),
- )
- @export_write_operation()
def leave(fqdn_listname, address):
"""Unsubscribe from a mailing list.
diff --git a/src/mailman/interfaces/rest.py b/src/mailman/interfaces/rest.py
index f5eb59bc9..9ec7914ad 100644
--- a/src/mailman/interfaces/rest.py
+++ b/src/mailman/interfaces/rest.py
@@ -26,14 +26,12 @@ __all__ = [
]
-from lazr.restful.declarations import error_status
from zope.interface import Interface
from mailman.core.errors import MailmanError
-@error_status(400)
class APIValueError(MailmanError, ValueError):
"""A `ValueError` from the REST API."""
diff --git a/src/mailman/interfaces/system.py b/src/mailman/interfaces/system.py
index 9f2e275fa..39156315f 100644
--- a/src/mailman/interfaces/system.py
+++ b/src/mailman/interfaces/system.py
@@ -25,9 +25,7 @@ __all__ = [
]
-from lazr.restful.declarations import export_as_webservice_entry, exported
-from zope.interface import Interface
-from zope.schema import TextLine
+from zope.interface import Interface, Attribute
from mailman.core.i18n import _
@@ -36,14 +34,6 @@ from mailman.core.i18n import _
class ISystem(Interface):
"""Information about the Mailman system."""
- export_as_webservice_entry()
+ mailman_version = Attribute('The GNU Mailman version.')
- mailman_version = exported(TextLine(
- title=_('Mailman version'),
- description=_('The GNU Mailman version.'),
- ))
-
- python_version = exported(TextLine(
- title=_('Python version'),
- description=_('The Python version.'),
- ))
+ python_version = Attribute('The Python version.')
diff --git a/src/mailman/rest/docs/basic.txt b/src/mailman/rest/docs/basic.txt
index 79abbfde1..6d928ab85 100644
--- a/src/mailman/rest/docs/basic.txt
+++ b/src/mailman/rest/docs/basic.txt
@@ -26,8 +26,7 @@ Non-existent links
When you try to access an admin link that doesn't exist, you get the
appropriate HTTP 404 Not Found error.
- >>> from urllib2 import urlopen
- >>> urlopen('http://localhost:8001/3.0/does-not-exist')
+ >>> dump_json('http://localhost:8001/3.0/does-not-exist')
Traceback (most recent call last):
...
HTTPError: HTTP Error 404: Not Found
diff --git a/src/mailman/rest/docs/domains.txt b/src/mailman/rest/docs/domains.txt
index ed9c6bc2f..cbb9e9fce 100644
--- a/src/mailman/rest/docs/domains.txt
+++ b/src/mailman/rest/docs/domains.txt
@@ -126,17 +126,13 @@ 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;charset=utf-8
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.
@@ -172,12 +168,9 @@ address.
... })
URL: http://localhost:8001/3.0/domains
content-length: 0
- content-type: text/plain;charset=utf-8
date: ...
location: http://localhost:8001/3.0/domains/my.example.com
- server: WSGIServer/... Python/...
- x-content-type-warning: guessed from content
- x-powered-by: Zope (www.zope.org), Python (www.python.org)
+ ...
>>> dump_json('http://localhost:8001/3.0/domains/my.example.com')
base_url: http://allmy.example.com
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index 5c42635cb..8a1e919bf 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -27,85 +27,185 @@ __all__ = [
]
+import json
+import hashlib
import logging
-# Don't use wsgiref.simple_server.make_server() because we need to override
-# BaseHTTPRequestHandler.log_message() so that logging output will go to the
-# proper Mailman logger instead of stderr, as is the default.
-from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
+from restish.app import RestishApp
+from restish import http, resource
+from wsgiref.simple_server import (
+ make_server as wsgi_server, WSGIRequestHandler)
-from lazr.restful import register_versioned_request_utility
-from lazr.restful.interfaces import (
- IServiceRootResource, IWebServiceClientRequest)
-from lazr.restful.simple import Request, RootResource
-from lazr.restful.wsgi import WSGIApplication
from zope.component import getUtility
from zope.interface import implements
-from zope.publisher.publish import publish
from mailman.config import config
from mailman.core.system import system
-from mailman.interfaces.domain import IDomain, IDomainCollection
+from mailman.interfaces.domain import (
+ BadDomainSpecificationError, IDomain, IDomainManager)
from mailman.interfaces.listmanager import IListManager
from mailman.interfaces.mailinglist import IMailingList
from mailman.interfaces.member import IMember
from mailman.interfaces.membership import ISubscriptionService
from mailman.interfaces.rest import IResolvePathNames
-from mailman.rest.publication import AdminWebServicePublication
+#from mailman.rest.publication import AdminWebServicePublication
+
+COMMASPACE = ', '
log = logging.getLogger('mailman.http')
-# Marker interfaces for multiversion lazr.restful.
-#
-# XXX 2010-02-16 barry Gah! lazr.restful's multiversion.txt document says
-# these classes should get generated, and the registrations should happen,
-# automatically. This is not the case AFAICT. Why?!
+class Root(resource.Resource):
+ """The RESTful root resource."""
-class I30Version(IWebServiceClientRequest):
- pass
+ @resource.child('3.0')
+ def api_version(self, request, segments):
+ return TopLevel()
-class IDevVersion(IWebServiceClientRequest):
- pass
+class TopLevel(resource.Resource):
+ """Top level collections and entries."""
+ @resource.child()
+ def system(self, request, segments):
+ response = dict(
+ mailman_version=system.mailman_version,
+ python_version=system.python_version,
+ resource_type_link='http://localhost:8001/3.0/#system',
+ self_link='http://localhost:8001/3.0/system',
+ )
+ etag = hashlib.sha1(repr(response)).hexdigest()
+ response['http_etag'] = '"{0}"'.format(etag)
+ return http.ok([], json.dumps(response))
-
-class AdminWebServiceRootResource(RootResource):
- """The lazr.restful non-versioned root resource."""
+ @resource.child()
+ def domains(self, request, segments):
+ if len(segments) == 0:
+ return AllDomains()
+ elif len(segments) == 1:
+ return ADomain(segments[0]), []
+ else:
+ return http.bad_request()
- implements(IResolvePathNames)
- # XXX 2010-02-16 barry lazr.restful really wants this class to exist and
- # be a subclass of RootResource. Our own traversal really wants this to
- # implement IResolvePathNames. RootResource says to override
- # _build_top_level_objects() to return the top-level objects, but that
- # appears to never be called by lazr.restful, so you've got me. I don't
- # understand this, which sucks, so just ensure that it doesn't do anything
- # useful so if/when I do understand this, I can resolve the conflict
- # between the way lazr.restful wants us to do things and the way our
- # traversal wants to do things.
- def _build_top_level_objects(self):
- """See `RootResource`."""
- raise NotImplementedError('Magic suddenly got invoked')
+class _DomainBase(resource.Resource):
+ """Shared base class for domain representations."""
- def get(self, name):
- """See `IResolvePathNames`."""
- top_names = dict(
- domains=getUtility(IDomainCollection),
- lists=getUtility(IListManager),
- members=getUtility(ISubscriptionService),
- system=system,
+ def _format_domain(self, domain):
+ """Format the data for a single domain."""
+ domain_data = dict(
+ base_url=domain.base_url,
+ contact_address=domain.contact_address,
+ description=domain.description,
+ email_host=domain.email_host,
+ resource_type_link='http://localhost:8001/3.0/#domain',
+ self_link='http://localhost:8001/3.0/domains/{0}'.format(
+ domain.email_host),
+ url_host=domain.url_host,
)
- return top_names.get(name)
+ etag = hashlib.sha1(repr(domain_data)).hexdigest()
+ domain_data['http_etag'] = '"{0}"'.format(etag)
+ return domain_data
+
+
+class ADomain(_DomainBase):
+ """A domain."""
+ def __init__(self, domain):
+ self._domain = domain
-class AdminWebServiceApplication(WSGIApplication):
- """A WSGI application for the admin REST interface."""
+ @resource.GET()
+ def domain(self, request):
+ """Return a single domain end-point."""
+ domain = getUtility(IDomainManager).get(self._domain)
+ if domain is None:
+ return http.not_found()
+ return http.ok([], json.dumps(self._format_domain(domain)))
+
+
+class AllDomains(_DomainBase):
+ """The domains."""
+
+ @resource.POST()
+ def create(self, request):
+ """Create a new domain."""
+ # XXX 2010-02-23 barry Sanity check the POST arguments by
+ # introspection of the target method, or via descriptors.
+ domain_manager = getUtility(IDomainManager)
+ try:
+ # Hmmm... webob gives this to us as a string, but we need
+ # unicodes. For backward compatibility with lazr.restful style
+ # requests, ignore any ws.op parameter.
+ kws = dict((key, unicode(value))
+ for key, value in request.POST.items()
+ if key != 'ws.op')
+ domain = domain_manager.add(**kws)
+ except BadDomainSpecificationError:
+ return http.bad_request([], 'Domain exists')
+ # wsgiref wants headers to be strings, not unicodes.
+ location = 'http://localhost:8001/3.0/domains/{0}'.format(
+ domain.email_host)
+ # Include no extra headers or body.
+ return http.created(str(location), [], None)
+
+ @resource.GET()
+ def container(self, request):
+ """Return the /domains end-point."""
+ domains = list(getUtility(IDomainManager))
+ if len(domains) == 0:
+ return http.ok(
+ [], json.dumps(dict(resource_type_link=
+ 'http://localhost:8001/3.0/#domains',
+ start=None,
+ total_size=0)))
+ entries = []
+ response = dict(
+ resource_type_link='http://localhost:8001/3.0/#domains',
+ start=0,
+ total_size=len(domains),
+ entries=entries,
+ )
+ for domain in domains:
+ domain_data = self._format_domain(domain)
+ entries.append(domain_data)
+ return http.ok([], json.dumps(response))
- # The only thing we need to override is the publication class.
- publication_class = AdminWebServicePublication
+
+## class AdminWebServiceRootResource(RootResource):
+## """The lazr.restful non-versioned root resource."""
+
+## implements(IResolvePathNames)
+
+## # XXX 2010-02-16 barry lazr.restful really wants this class to exist and
+## # be a subclass of RootResource. Our own traversal really wants this to
+## # implement IResolvePathNames. RootResource says to override
+## # _build_top_level_objects() to return the top-level objects, but that
+## # appears to never be called by lazr.restful, so you've got me. I don't
+## # understand this, which sucks, so just ensure that it doesn't do anything
+## # useful so if/when I do understand this, I can resolve the conflict
+## # between the way lazr.restful wants us to do things and the way our
+## # traversal wants to do things.
+## def _build_top_level_objects(self):
+## """See `RootResource`."""
+## raise NotImplementedError('Magic suddenly got invoked')
+
+## def get(self, name):
+## """See `IResolvePathNames`."""
+## top_names = dict(
+## domains=getUtility(IDomainCollection),
+## lists=getUtility(IListManager),
+## members=getUtility(ISubscriptionService),
+## system=system,
+## )
+## return top_names.get(name)
+
+
+## class AdminWebServiceApplication(WSGIApplication):
+## """A WSGI application for the admin REST interface."""
+
+## # The only thing we need to override is the publication class.
+## publication_class = AdminWebServicePublication
class AdminWebServiceWSGIRequestHandler(WSGIRequestHandler):
@@ -116,16 +216,29 @@ class AdminWebServiceWSGIRequestHandler(WSGIRequestHandler):
log.info('%s - - %s', self.address_string(), format % args)
+class AdminWebServiceApplication(RestishApp):
+ """Interpose in the restish request processor."""
+
+ def __call__(self, environ, start_response):
+ """See `RestishApp`."""
+ try:
+ response = super(AdminWebServiceApplication, self).__call__(
+ environ, start_response)
+ except:
+ config.db.abort()
+ raise
+ else:
+ config.db.commit()
+ return response
+
+
def make_server():
"""Create the WSGI admin REST server."""
- # XXX 2010-02-16 barry Gah! lazr.restful's multiversion.txt document says
- # these classes should get generated, and the registrations should happen,
- # automatically. This is not the case AFAICT. Why?!
- register_versioned_request_utility(I30Version, '3.0')
- register_versioned_request_utility(IDevVersion, 'dev')
+ app = AdminWebServiceApplication(Root())
host = config.webservice.hostname
port = int(config.webservice.port)
- server = WSGIServer((host, port), AdminWebServiceWSGIRequestHandler)
- server.set_app(AdminWebServiceApplication)
+ server = wsgi_server(
+ host, port, app,
+ handler_class=AdminWebServiceWSGIRequestHandler)
return server