1 # Copyright (C) 2016-2019 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
20 from mailman
.interfaces
.template
import ALL_TEMPLATES
, ITemplateManager
21 from mailman
.rest
.helpers
import (
22 CollectionMixin
, bad_request
, etag
, no_content
, not_found
, okay
)
23 from mailman
.rest
.validator
import Validator
24 from operator
import attrgetter
25 from public
import public
26 from zope
.component
import getUtility
29 class _URIBase(CollectionMixin
):
30 def __init__(self
, context
):
31 self
._context
= context
33 def _resource_as_dict(self
, template
):
37 self_link
=self
.api
.path_to('{}/uris/{}'.format(
38 self
._prefix
, template
.name
)),
40 if template
.username
is not None and template
.password
is not None:
41 resource
['username'] = template
.username
42 resource
['password'] = template
.password
45 def _get_collection(self
, request
):
46 manager
= getUtility(ITemplateManager
)
49 template
= manager
.raw(uri
, self
._raw
_context
)
50 if template
is not None:
51 collection
.append(template
)
52 return sorted(collection
, key
=attrgetter('name'))
54 def on_get(self
, request
, response
):
55 resource
= self
._make
_collection
(request
)
56 resource
['self_link'] = self
.api
.path_to(
57 '{}/uris'.format(self
._prefix
))
58 okay(response
, etag(resource
))
60 def _patch_put(self
, request
, response
, is_optional
):
61 kws
= {uri
: str for uri
in self
.URIs
}
62 optionals
= ['username', 'password']
64 optionals
.extend(self
.URIs
)
65 # When PATCHing or PUTing all uris, a single optional
66 # username/password applies to them all.
69 kws
['_optional'] = optionals
71 arguments
= Validator(**kws
)(request
)
72 except ValueError as error
:
73 bad_request(response
, str(error
))
75 username
= arguments
.pop('username', None)
76 password
= arguments
.pop('password', None)
77 if not username
and not password
:
78 # Normalize arguments.
80 elif username
and password
:
81 # It's fine if both are specified.
82 set_kws
= dict(username
=username
, password
=password
)
85 'Specify both username and password, or neither')
87 manager
= getUtility(ITemplateManager
)
88 for key
, value
in arguments
.items():
90 # The empty string is equivalent to DELETE. Yeah, this isn't
91 # very RESTful, but practicality beats purity.
92 manager
.delete(key
, self
._raw
_context
)
94 manager
.set(key
, self
._raw
_context
, value
, **set_kws
)
97 def on_put(self
, request
, response
):
98 self
._patch
_put
(request
, response
, is_optional
=False)
100 def on_patch(self
, request
, response
):
101 self
._patch
_put
(request
, response
, is_optional
=True)
103 def on_delete(self
, request
, response
):
104 manager
= getUtility(ITemplateManager
)
105 for uri
in self
.URIs
:
106 manager
.delete(uri
, self
._raw
_context
)
110 class _ListURIBase(_URIBase
):
111 def __init__(self
, context
):
112 super().__init
__(context
)
113 self
._raw
_context
= context
.list_id
114 self
._prefix
= 'lists/{}'.format(context
.list_id
)
118 class AllListURIs(_ListURIBase
):
119 URIs
= [name
for name
in ALL_TEMPLATES
if name
.startswith('list:')]
121 def __init__(self
, context
):
122 super().__init
__(context
)
126 class AListURI(_ListURIBase
):
127 def __init__(self
, context
, template
):
128 super().__init
__(context
)
129 self
.URIs
= [template
]
130 self
._template
= template
132 def on_get(self
, request
, response
):
133 template
= getUtility(ITemplateManager
).raw(
134 self
._template
, self
._raw
_context
)
138 resource
= dict(uri
=template
.uri
)
139 resource
['self_link'] = self
.api
.path_to(
140 '{}/uris/{}'.format(self
._prefix
, self
._template
))
141 okay(response
, etag(resource
))
144 class _DomainURIBase(_URIBase
):
145 def __init__(self
, context
):
146 super().__init
__(context
)
147 self
._raw
_context
= context
.mail_host
148 self
._prefix
= 'domains/{}'.format(context
.mail_host
)
152 class AllDomainURIs(_DomainURIBase
):
153 URIs
= [name
for name
in ALL_TEMPLATES
154 if name
.startswith('list:') or name
.startswith('domain:')]
158 class ADomainURI(_DomainURIBase
):
159 def __init__(self
, context
, template
):
160 super().__init
__(context
)
161 self
.URIs
= [template
]
162 self
._template
= template
164 def on_get(self
, request
, response
):
165 template
= getUtility(ITemplateManager
).raw(
166 self
._template
, self
._raw
_context
)
170 resource
= dict(uri
=template
.uri
)
171 resource
['self_link'] = self
.api
.path_to(
172 '{}/uris/{}'.format(self
._prefix
, self
._template
))
173 okay(response
, etag(resource
))
176 class _SiteURIBase(_URIBase
):
178 super().__init
__(None)
179 self
._raw
_context
= None
184 class AllSiteURIs(_SiteURIBase
):
185 URIs
= [name
for name
in ALL_TEMPLATES
]
189 class ASiteURI(_SiteURIBase
):
190 def __init__(self
, template
):
192 self
.URIs
= [template
]
193 self
._template
= template
195 def on_get(self
, request
, response
):
196 template
= getUtility(ITemplateManager
).raw(self
._template
, None)
200 resource
= dict(uri
=template
.uri
)
201 resource
['self_link'] = self
.api
.path_to(
202 'uris/{}'.format(self
._template
))
203 okay(response
, etag(resource
))