Checkpointing.
[mailman.git] / src / mailman / rest / post_moderation.py
blob6156fa39f1f821c512de0050a0aead56ab7dbc1e
1 # Copyright (C) 2012-2015 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)
8 # any later version.
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
13 # more details.
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/>.
18 """REST API for held message moderation."""
20 __all__ = [
21 'HeldMessage',
22 'HeldMessages',
26 from mailman.app.moderator import handle_message
27 from mailman.interfaces.action import Action
28 from mailman.interfaces.messages import IMessageStore
29 from mailman.interfaces.requests import IListRequests, RequestType
30 from mailman.rest.helpers import (
31 CollectionMixin, bad_request, child, etag, no_content, not_found, okay)
32 from mailman.rest.validator import Validator, enum_validator
33 from zope.component import getUtility
37 class _ModerationBase:
38 """Common base class."""
40 def _make_resource(self, request_id):
41 requests = IListRequests(self._mlist)
42 results = requests.get_request(request_id)
43 if results is None:
44 return None
45 key, data = results
46 resource = dict(key=key, request_id=request_id)
47 # Flatten the IRequest payload into the JSON representation.
48 resource.update(data)
49 # Check for a matching request type, and insert the type name into the
50 # resource.
51 request_type = RequestType[resource.pop('_request_type')]
52 if request_type is not RequestType.held_message:
53 return None
54 resource['type'] = RequestType.held_message.name
55 # This key isn't what you think it is. Usually, it's the Pendable
56 # record's row id, which isn't helpful at all. If it's not there,
57 # that's fine too.
58 resource.pop('id', None)
59 return resource
63 class _HeldMessageBase(_ModerationBase):
64 """Held messages are a little different."""
66 def _make_resource(self, request_id):
67 resource = super(_HeldMessageBase, self)._make_resource(request_id)
68 if resource is None:
69 return None
70 # Grab the message and insert its text representation into the
71 # resource. XXX See LP: #967954
72 key = resource.pop('key')
73 msg = getUtility(IMessageStore).get_message_by_id(key)
74 resource['msg'] = msg.as_string()
75 # Some of the _mod_* keys we want to rename and place into the JSON
76 # resource. Others we can drop. Since we're mutating the dictionary,
77 # we need to make a copy of the keys. When you port this to Python 3,
78 # you'll need to list()-ify the .keys() dictionary view.
79 for key in list(resource):
80 if key in ('_mod_subject', '_mod_hold_date', '_mod_reason',
81 '_mod_sender', '_mod_message_id'):
82 resource[key[5:]] = resource.pop(key)
83 elif key.startswith('_mod_'):
84 del resource[key]
85 # Also, held message resources will always be this type, so ignore
86 # this key value.
87 del resource['type']
88 return resource
91 class HeldMessage(_HeldMessageBase):
92 """Resource for moderating a held message."""
94 def __init__(self, mlist, request_id):
95 self._mlist = mlist
96 self._request_id = request_id
98 def on_get(self, request, response):
99 try:
100 request_id = int(self._request_id)
101 except ValueError:
102 bad_request(response)
103 return
104 resource = self._make_resource(request_id)
105 if resource is None:
106 not_found(response)
107 else:
108 okay(response, etag(resource))
110 def on_post(self, request, response):
111 try:
112 validator = Validator(action=enum_validator(Action))
113 arguments = validator(request)
114 except ValueError as error:
115 bad_request(response, str(error))
116 return
117 requests = IListRequests(self._mlist)
118 try:
119 request_id = int(self._request_id)
120 except ValueError:
121 bad_request(response)
122 return
123 results = requests.get_request(request_id, RequestType.held_message)
124 if results is None:
125 not_found(response)
126 else:
127 handle_message(self._mlist, request_id, **arguments)
128 no_content(response)
132 class HeldMessages(_HeldMessageBase, CollectionMixin):
133 """Resource for messages held for moderation."""
135 def __init__(self, mlist):
136 self._mlist = mlist
137 self._requests = None
139 def _resource_as_dict(self, request):
140 """See `CollectionMixin`."""
141 return self._make_resource(request.id)
143 def _get_collection(self, request):
144 requests = IListRequests(self._mlist)
145 self._requests = requests
146 return list(requests.of_type(RequestType.held_message))
148 def on_get(self, request, response):
149 """/lists/listname/held"""
150 resource = self._make_collection(request)
151 okay(response, etag(resource))
153 @child(r'^(?P<id>[^/]+)')
154 def message(self, request, segments, **kw):
155 return HeldMessage(self._mlist, kw['id'])