~rashi007/mailman/docsfix

« back to all changes in this revision

Viewing changes to src/mailman/rest/root.py

  • Committer: Barry Warsaw
  • Date: 2014-11-15 17:01:30 UTC
  • mfrom: (7251.4.19 falcon)
  • Revision ID: barry@list.org-20141115170130-0log69qu4j6ctkfj
s/restish/falcon/

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    ]
26
26
 
27
27
 
 
28
import falcon
 
29
 
28
30
from base64 import b64decode
29
 
from restish import guard, http, resource
30
31
from zope.component import getUtility
31
32
 
32
33
from mailman.config import config
33
34
from mailman.core.constants import system_preferences
34
35
from mailman.core.system import system
35
36
from mailman.interfaces.listmanager import IListManager
36
 
from mailman.interfaces.styles import IStyleManager
37
37
from mailman.rest.addresses import AllAddresses, AnAddress
38
38
from mailman.rest.domains import ADomain, AllDomains
39
 
from mailman.rest.helpers import etag, path_to
40
 
from mailman.rest.lists import AList, AllLists
 
39
from mailman.rest.helpers import (
 
40
    BadRequest, NotFound, child, etag, okay, path_to)
 
41
from mailman.rest.lists import AList, AllLists, Styles
41
42
from mailman.rest.members import AMember, AllMembers, FindMembers
42
43
from mailman.rest.preferences import ReadOnlyPreferences
43
44
from mailman.rest.templates import TemplateFinder
45
46
 
46
47
 
47
48
 
48
 
def webservice_auth_checker(request, obj):
49
 
    auth = request.environ.get('HTTP_AUTHORIZATION', '')
50
 
    if auth.startswith('Basic '):
51
 
        credentials = b64decode(auth[6:])
52
 
        username, password = credentials.split(':', 1)
53
 
        if (username != config.webservice.admin_user or
54
 
            password != config.webservice.admin_pass):
55
 
            # Not authorized.
56
 
            raise guard.GuardError(b'User is not authorized for the REST API')
57
 
    else:
58
 
        raise guard.GuardError(b'The REST API requires authentication')
59
 
 
60
 
 
61
 
class Root(resource.Resource):
 
49
class Root:
62
50
    """The RESTful root resource.
63
51
 
64
52
    At the root of the tree are the API version numbers.  Everything else
67
55
    always be the case though.
68
56
    """
69
57
 
70
 
    @resource.child(config.webservice.api_version)
71
 
    @guard.guard(webservice_auth_checker)
 
58
    @child(config.webservice.api_version)
72
59
    def api_version(self, request, segments):
 
60
        # We have to do this here instead of in a @falcon.before() handler
 
61
        # because those handlers are not compatible with our custom traversal
 
62
        # logic.  Specifically, falcon's before/after handlers will call the
 
63
        # responder, but the method we're wrapping isn't a responder, it's a
 
64
        # child traversal method.  There's no way to cause the thing that
 
65
        # calls the before hook to follow through with the child traversal in
 
66
        # the case where no error is raised.
 
67
        if request.auth is None:
 
68
            raise falcon.HTTPUnauthorized(
 
69
                b'401 Unauthorized',
 
70
                b'The REST API requires authentication')
 
71
        if request.auth.startswith('Basic '):
 
72
            credentials = b64decode(request.auth[6:])
 
73
            username, password = credentials.split(':', 1)
 
74
            if (username != config.webservice.admin_user or
 
75
                password != config.webservice.admin_pass):
 
76
                # Not authorized.
 
77
                raise falcon.HTTPUnauthorized(
 
78
                    b'401 Unauthorized',
 
79
                    b'User is not authorized for the REST API')
73
80
        return TopLevel()
74
81
 
75
82
 
76
 
class TopLevel(resource.Resource):
 
83
class System:
 
84
    def on_get(self, request, response):
 
85
        """/<api>/system"""
 
86
        resource = dict(
 
87
            mailman_version=system.mailman_version,
 
88
            python_version=system.python_version,
 
89
            self_link=path_to('system'),
 
90
            )
 
91
        okay(response, etag(resource))
 
92
 
 
93
 
 
94
class TopLevel:
77
95
    """Top level collections and entries."""
78
96
 
79
 
    @resource.child()
 
97
    @child()
80
98
    def system(self, request, segments):
81
99
        """/<api>/system"""
82
100
        if len(segments) == 0:
83
 
            resource = dict(
84
 
                mailman_version=system.mailman_version,
85
 
                python_version=system.python_version,
86
 
                self_link=path_to('system'),
87
 
                )
 
101
            return System()
88
102
        elif len(segments) > 1:
89
 
            return http.bad_request()
 
103
            return BadRequest(), []
90
104
        elif segments[0] == 'preferences':
91
105
            return ReadOnlyPreferences(system_preferences, 'system'), []
92
106
        else:
93
 
            return http.bad_request()
94
 
        return http.ok([], etag(resource))
 
107
            return NotFound(), []
95
108
 
96
 
    @resource.child()
 
109
    @child()
97
110
    def addresses(self, request, segments):
98
111
        """/<api>/addresses
99
112
           /<api>/addresses/<email>
104
117
            email = segments.pop(0)
105
118
            return AnAddress(email), segments
106
119
 
107
 
    @resource.child()
 
120
    @child()
108
121
    def domains(self, request, segments):
109
122
        """/<api>/domains
110
123
           /<api>/domains/<domain>
115
128
            domain = segments.pop(0)
116
129
            return ADomain(domain), segments
117
130
 
118
 
    @resource.child()
 
131
    @child()
119
132
    def lists(self, request, segments):
120
133
        """/<api>/lists
121
134
           /<api>/lists/<list>
124
137
        if len(segments) == 0:
125
138
            return AllLists()
126
139
        elif len(segments) == 1 and segments[0] == 'styles':
127
 
            manager = getUtility(IStyleManager)
128
 
            style_names = sorted(style.name for style in manager.styles)
129
 
            resource = dict(style_names=style_names,
130
 
                            default=config.styles.default)
131
 
            return http.ok([], etag(resource))
 
140
            return Styles(), []
132
141
        else:
133
142
            # list-id is preferred, but for backward compatibility,
134
143
            # fqdn_listname is also accepted.
135
144
            list_identifier = segments.pop(0)
136
145
            return AList(list_identifier), segments
137
146
 
138
 
    @resource.child()
 
147
    @child()
139
148
    def members(self, request, segments):
140
149
        """/<api>/members"""
141
150
        if len(segments) == 0:
148
157
        else:
149
158
            return AMember(segment), segments
150
159
 
151
 
    @resource.child()
 
160
    @child()
152
161
    def users(self, request, segments):
153
162
        """/<api>/users"""
154
163
        if len(segments) == 0:
157
166
            user_id = segments.pop(0)
158
167
            return AUser(user_id), segments
159
168
 
160
 
    @resource.child()
 
169
    @child()
161
170
    def templates(self, request, segments):
162
171
        """/<api>/templates/<fqdn_listname>/<template>/[<language>]
163
172
 
169
178
            fqdn_listname, template = segments
170
179
            language = 'en'
171
180
        else:
172
 
            return http.bad_request()
 
181
            return BadRequest(), []
173
182
        mlist = getUtility(IListManager).get(fqdn_listname)
174
183
        if mlist is None:
175
 
            return http.not_found()
 
184
            return NotFound(), []
176
185
        # XXX dig out content-type from request
177
186
        content_type = None
178
187
        return TemplateFinder(