summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/app/registrar.py17
-rw-r--r--src/mailman/config/config.py10
-rw-r--r--src/mailman/config/configure.zcml27
-rw-r--r--src/mailman/config/schema.cfg2
-rw-r--r--src/mailman/core/initialize.py16
-rw-r--r--src/mailman/database/autorespond.py17
-rw-r--r--src/mailman/database/mailinglist.py17
-rw-r--r--src/mailman/interfaces/domain.py70
-rw-r--r--src/mailman/rest/adapters.py47
-rw-r--r--src/mailman/rest/configuration.py2
-rw-r--r--src/mailman/rest/configure.zcml7
-rw-r--r--src/mailman/rest/docs/domains.txt8
-rw-r--r--src/mailman/rest/root.py7
-rw-r--r--src/mailman/rest/urls.py7
-rw-r--r--src/mailman/rest/webservice.py6
15 files changed, 157 insertions, 103 deletions
diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py
index 0cd43d484..4ec7991d6 100644
--- a/src/mailman/app/registrar.py
+++ b/src/mailman/app/registrar.py
@@ -22,7 +22,6 @@ from __future__ import unicode_literals
__metaclass__ = type
__all__ = [
'Registrar',
- 'adapt_domain_to_registrar',
]
@@ -145,19 +144,3 @@ class Registrar:
def discard(self, token):
# Throw the record away.
config.db.pendings.confirm(token)
-
-
-
-def adapt_domain_to_registrar(iface, obj):
- """Adapt `IDomain` to `IRegistrar`.
-
- :param iface: The interface to adapt to.
- :type iface: `zope.interface.Interface`
- :param obj: The object being adapted.
- :type obj: `IDomain`
- :return: An `IRegistrar` instance if adaptation succeeded or None if it
- didn't.
- """
- return (Registrar(obj)
- if IDomain.providedBy(obj) and iface is IRegistrar
- else None)
diff --git a/src/mailman/config/config.py b/src/mailman/config/config.py
index 4ae2e85be..5b7f51400 100644
--- a/src/mailman/config/config.py
+++ b/src/mailman/config/config.py
@@ -32,6 +32,7 @@ import logging
from lazr.config import ConfigSchema, as_boolean
from pkg_resources import resource_stream
+from zope.interface import Interface, implements
from mailman import version
from mailman.core import errors
@@ -46,9 +47,16 @@ SPACE = ' '
-class Configuration(object):
+class IConfiguration(Interface):
+ """Marker interface; used for adaptation in the REST API."""
+
+
+
+class Configuration:
"""The core global configuration object."""
+ implements(IConfiguration)
+
def __init__(self):
self.domains = {} # email host -> IDomain
self.switchboards = {}
diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml
new file mode 100644
index 000000000..405baa8bf
--- /dev/null
+++ b/src/mailman/config/configure.zcml
@@ -0,0 +1,27 @@
+<!-- -*- xml -*- -->
+<configure
+ xmlns="http://namespaces.zope.org/zope">
+
+ <include package="mailman.rest" file="configure.zcml"/>
+
+ <!-- adapters -->
+
+ <adapter
+ for="mailman.interfaces.domain.IDomain"
+ provides="mailman.interfaces.registrar.IRegistrar"
+ factory="mailman.app.registrar.Registrar"
+ />
+
+ <adapter
+ for="mailman.interfaces.mailinglist.IMailingList"
+ provides="mailman.interfaces.autorespond.IAutoResponseSet"
+ factory="mailman.database.autorespond.AutoResponseSet"
+ />
+
+ <adapter
+ for="mailman.interfaces.mailinglist.IMailingList"
+ provides="mailman.interfaces.mailinglist.IAcceptableAliasSet"
+ factory="mailman.database.mailinglist.AcceptableAliasSet"
+ />
+
+</configure>
diff --git a/src/mailman/config/schema.cfg b/src/mailman/config/schema.cfg
index e32a3896a..103ffb1de 100644
--- a/src/mailman/config/schema.cfg
+++ b/src/mailman/config/schema.cfg
@@ -226,7 +226,7 @@ port: 8001
use_https: no
# Default view permission for the admin web service.
-view_permission: zope.Public
+view_permission: None
# Whether or not to show tracebacks in an HTTP response for a request that
# raised an exception.
diff --git a/src/mailman/core/initialize.py b/src/mailman/core/initialize.py
index 885174fb0..8fc2150fb 100644
--- a/src/mailman/core/initialize.py
+++ b/src/mailman/core/initialize.py
@@ -38,7 +38,8 @@ __all__ = [
import os
import sys
-from zope.interface.interface import adapter_hooks
+from pkg_resources import resource_string
+from zope.configuration import xmlconfig
from zope.interface.verify import verifyObject
import mailman.config.config
@@ -82,6 +83,7 @@ def initialize_1(config_path=None, propagate_logs=None):
def initialize_2(debug=False):
"""Second initialization step.
+ * Pre-hook
* Rules
* Chains
* Pipelines
@@ -117,15 +119,11 @@ def initialize_2(debug=False):
def initialize_3():
"""Third initialization step.
- * Adapters
+ * Zope component architecture
+ * Post-hook
"""
- from mailman.app.registrar import adapt_domain_to_registrar
- adapter_hooks.append(adapt_domain_to_registrar)
- from mailman.database.autorespond import adapt_mailing_list_to_response_set
- adapter_hooks.append(adapt_mailing_list_to_response_set)
- from mailman.database.mailinglist import (
- adapt_mailing_list_to_acceptable_alias_set)
- adapter_hooks.append(adapt_mailing_list_to_acceptable_alias_set)
+ zcml = resource_string('mailman.config', 'configure.zcml')
+ xmlconfig.string(zcml)
# Run the post-hook if there is one.
config = mailman.config.config
if config.mailman.post_hook:
diff --git a/src/mailman/database/autorespond.py b/src/mailman/database/autorespond.py
index d65e8ed07..0a84f30e3 100644
--- a/src/mailman/database/autorespond.py
+++ b/src/mailman/database/autorespond.py
@@ -23,7 +23,6 @@ __metaclass__ = type
__all__ = [
'AutoResponseRecord',
'AutoResponseSet',
- 'adapt_mailing_list_to_response_set',
]
@@ -92,19 +91,3 @@ class AutoResponseSet:
AutoResponseRecord.response_type == response_type)
).order_by(Desc(AutoResponseRecord.date_sent))
return (None if results.count() == 0 else results.first())
-
-
-
-def adapt_mailing_list_to_response_set(iface, obj):
- """Adapt an `IMailingList` to an `IAutoResponseSet`.
-
- :param iface: The interface to adapt to.
- :type iface: `zope.interface.Interface`
- :param obj: The object being adapted.
- :type obj: `IMailingList`
- :return: An `IAutoResponseSet` instance if adaptation succeeded or None if
- it didn't.
- """
- return (AutoResponseSet(obj)
- if IMailingList.providedBy(obj) and iface is IAutoResponseSet
- else None)
diff --git a/src/mailman/database/mailinglist.py b/src/mailman/database/mailinglist.py
index b8cf3e01c..f08adfd8b 100644
--- a/src/mailman/database/mailinglist.py
+++ b/src/mailman/database/mailinglist.py
@@ -22,7 +22,6 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'MailingList',
- 'adapt_mailing_list_to_acceptable_alias_set',
]
@@ -462,19 +461,3 @@ class AcceptableAliasSet:
AcceptableAlias.mailing_list == self._mailing_list)
for alias in aliases:
yield alias.alias
-
-
-
-def adapt_mailing_list_to_acceptable_alias_set(iface, obj):
- """Adapt an `IMailingList` to an `IAcceptableAliasSet`.
-
- :param iface: The interface to adapt to.
- :type iface: `zope.interface.Interface`
- :param obj: The object being adapted.
- :type obj: `IMailingList`
- :return: An `IAcceptableAliasSet` instance if adaptation succeeded or None
- if it didn't.
- """
- return (AcceptableAliasSet(obj)
- if IMailingList.providedBy(obj) and iface is IAcceptableAliasSet
- else None)
diff --git a/src/mailman/interfaces/domain.py b/src/mailman/interfaces/domain.py
index 773290bc5..0692d21d5 100644
--- a/src/mailman/interfaces/domain.py
+++ b/src/mailman/interfaces/domain.py
@@ -22,49 +22,54 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'IDomain',
+ 'IDomainSet',
]
+from lazr.restful.declarations import (
+ collection_default_content, export_as_webservice_collection,
+ export_as_webservice_entry, exported)
from zope.interface import Interface, Attribute
+from zope.schema import TextLine
+
+from mailman.i18n import _
class IDomain(Interface):
"""Interface representing domains."""
- email_host = Attribute(
- """The host name for email for this domain.
-
- :type: string
- """)
-
- url_host = Attribute(
- """The host name for the web interface for this domain.
-
- :type: string
- """)
-
- base_url = Attribute(
- """The base url for the Mailman server at this domain.
-
- The base url includes the scheme and host name.
+ export_as_webservice_entry()
- :type: string
- """)
+ email_host = exported(TextLine(
+ title=_('Email host name'),
+ description=_('The host name for email for this domain.'),
+ ))
- description = Attribute(
- """The human readable description of the domain name.
+ url_host = exported(TextLine(
+ title=_('Web host name'),
+ description=_('The host name for the web interface for this domain.')
+ ))
- :type: string
- """)
+ 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."""),
+ ))
- contact_address = Attribute(
- """The contact address for the human at this domain.
+ description = exported(TextLine(
+ title=_('Description'),
+ description=_('The human readable description of the domain name.'),
+ ))
- E.g. postmaster@example.com
+ contact_address = exported(TextLine(
+ title=_('Contact address'),
+ description=_("""\
+ The contact address for the human at this domain.
- :type: string
- """)
+ E.g. postmaster@example.com"""),
+ ))
def confirm_address(token=''):
"""The address used for various forms of email confirmation.
@@ -83,3 +88,14 @@ class IDomain(Interface):
:return: The confirmation url.
:rtype: string
"""
+
+
+
+class IDomainSet(Interface):
+ """The set of all known domains."""
+
+ export_as_webservice_collection(IDomain)
+
+ @collection_default_content()
+ def __iter__():
+ """Iterate over all domains."""
diff --git a/src/mailman/rest/adapters.py b/src/mailman/rest/adapters.py
new file mode 100644
index 000000000..611e1f976
--- /dev/null
+++ b/src/mailman/rest/adapters.py
@@ -0,0 +1,47 @@
+# Copyright (C) 2009 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""Module stuff."""
+
+from __future__ import absolute_import, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'DomainSet',
+ ]
+
+
+from zope.interface import implements
+
+from mailman.interfaces.domain import IDomainSet
+
+
+
+class DomainSet:
+ """Sets of known domains."""
+
+ implements(IDomainSet)
+
+ __name__ = 'domains'
+
+ def __init__(self, config):
+ self._config = config
+
+ def __iter__(self):
+ """See `IDomainSet`."""
+ domains = self._config.domains
+ return [domains[domain] for domain in sorted(domains)]
diff --git a/src/mailman/rest/configuration.py b/src/mailman/rest/configuration.py
index 19ad6a09d..af1f90551 100644
--- a/src/mailman/rest/configuration.py
+++ b/src/mailman/rest/configuration.py
@@ -42,6 +42,8 @@ class AdminWebServiceConfiguration:
@property
def view_permission(self):
+ if config.webservice.view_permission.lower() == 'none':
+ return None
return config.webservice.view_permission
path_override = None
diff --git a/src/mailman/rest/configure.zcml b/src/mailman/rest/configure.zcml
index 70155bf67..c6d32ac58 100644
--- a/src/mailman/rest/configure.zcml
+++ b/src/mailman/rest/configure.zcml
@@ -9,6 +9,7 @@
<include package="lazr.restful" file="configure.zcml"/>
<webservice:register module="mailman.interfaces.system" />
+ <webservice:register module="mailman.interfaces.domain" />
<adapter
for="zope.interface.Interface
@@ -17,6 +18,12 @@
factory="mailman.rest.urls.AbsoluteURLMapper"
/>
+ <adapter
+ for="mailman.config.config.IConfiguration"
+ provides="mailman.interfaces.domain.IDomainSet"
+ factory="mailman.rest.adapters.DomainSet"
+ />
+
<utility
factory="mailman.rest.configuration.AdminWebServiceConfiguration"
provides="lazr.restful.interfaces.IWebServiceConfiguration">
diff --git a/src/mailman/rest/docs/domains.txt b/src/mailman/rest/docs/domains.txt
new file mode 100644
index 000000000..e3ea902bc
--- /dev/null
+++ b/src/mailman/rest/docs/domains.txt
@@ -0,0 +1,8 @@
+=======
+Domains
+=======
+
+The REST API can be queried for the set of known domains.
+
+ >>> dump_json('http://localhost:8001/3.0/domains')
+ XXX
diff --git a/src/mailman/rest/root.py b/src/mailman/rest/root.py
index 620739287..a6dc26248 100644
--- a/src/mailman/rest/root.py
+++ b/src/mailman/rest/root.py
@@ -41,13 +41,6 @@ from mailman.core.system import system
class AdminWebServiceRootResource(ServiceRootResource):
"""The root of the Mailman RESTful admin web service."""
- def get(self, name):
- """See `IHasGet`."""
- top_level = {
- 'sys': system,
- }
- return top_level.get(name)
-
class AdminWebServiceRootAbsoluteURL:
"""A basic implementation of `IAbsoluteURL` for the root object."""
diff --git a/src/mailman/rest/urls.py b/src/mailman/rest/urls.py
index cdd921d4e..5d8d7930b 100644
--- a/src/mailman/rest/urls.py
+++ b/src/mailman/rest/urls.py
@@ -69,7 +69,8 @@ class AbsoluteURLMapper:
# Special cases.
if isinstance(ob, AdminWebServiceApplication):
return ''
- urls = {
- system: 'system',
- }
+ urls = dict(
+ system='system',
+ domains='domains',
+ )
return urls[ob]
diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py
index bf1012203..a76ad3863 100644
--- a/src/mailman/rest/webservice.py
+++ b/src/mailman/rest/webservice.py
@@ -35,14 +35,13 @@ import logging
from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
from lazr.restful.publisher import WebServiceRequestTraversal
-from pkg_resources import resource_string
-from zope.configuration import xmlconfig
from zope.interface import implements
from zope.publisher.browser import BrowserRequest
from zope.publisher.publish import publish
from mailman.config import config
from mailman.core.system import system
+from mailman.interfaces.domain import IDomainSet
from mailman.interfaces.rest import IResolvePathNames
from mailman.rest.publication import AdminWebServicePublication
@@ -84,6 +83,7 @@ class AdminWebServiceApplication:
"""Maps root names to resources."""
top_level = dict(
system=system,
+ domains=IDomainSet(config),
)
return top_level.get(name)
@@ -99,8 +99,6 @@ class AdminWebServiceWSGIRequestHandler(WSGIRequestHandler):
def make_server():
"""Create the WSGI admin REST server."""
- zcml = resource_string('mailman.rest', 'configure.zcml')
- xmlconfig.string(zcml)
host = config.webservice.hostname
port = int(config.webservice.port)
server = WSGIServer((host, port), AdminWebServiceWSGIRequestHandler)