~barry/mailman/events-and-web

« back to all changes in this revision

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

  • Committer: Barry Warsaw
  • Date: 2012-09-22 17:35:24 UTC
  • Revision ID: barry@list.org-20120922173524-55hz5ltrdzukupdt
 * You can now PUT and PATCH on user resources to change the user's display
   name or password.  For passwords, you pass in the clear text password and
   Mailman will hash it before storing.

Also:

 * Major refactoring of validators for PUT and PATCH.  Pull the common logic
   out of configuration.py and put it in a PatchValidator class in
   helpers.py.  Also move GetterSetter to helpers.py
 * Add new exception classes RESTError, UnknownPATCHRequestError,
   ReadOnlyPATCHRequestError.  These are used in the PatchValidator.
 * Added Validator.update() which works nicely for PATCH and PUT.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
__metaclass__ = type
23
23
__all__ = [
 
24
    'PatchValidator',
24
25
    'Validator',
25
26
    'enum_validator',
26
27
    'language_validator',
31
32
from uuid import UUID
32
33
from zope.component import getUtility
33
34
 
 
35
from mailman.core.errors import (
 
36
    ReadOnlyPATCHRequestError, UnknownPATCHRequestError)
34
37
from mailman.interfaces.languages import ILanguageManager
35
38
 
36
39
 
119
122
            missing = COMMASPACE.join(sorted(required_keys - value_keys))
120
123
            raise ValueError('Missing parameters: {0}'.format(missing))
121
124
        return values
 
125
 
 
126
    def update(self, obj, request):
 
127
        """Update the object with the values in the request.
 
128
 
 
129
        This first validates and converts the attributes in the request, then
 
130
        updates the given object with the newly converted values.
 
131
 
 
132
        :param obj: The object to update.
 
133
        :type obj: object
 
134
        :param request: The HTTP request.
 
135
        :raises ValueError: if conversion failed for some attribute.
 
136
        """
 
137
        for key, value in self.__call__(request).items():
 
138
            self._converters[key].put(obj, key, value)
 
139
 
 
140
 
 
141
 
 
142
class PatchValidator(Validator):
 
143
    """Create a special validator for PATCH requests.
 
144
 
 
145
    PATCH is different than PUT because with the latter, you're changing the
 
146
    entire resource, so all expected attributes must exist.  With the former,
 
147
    you're only changing a subset of the attributes, so you only validate the
 
148
    ones that exist in the request.
 
149
    """
 
150
    def __init__(self, request, converters):
 
151
        """Create a validator for the PATCH request.
 
152
 
 
153
        :param request: The request object, which must have a .PATCH
 
154
            attribute.
 
155
        :param converters: A mapping of attribute names to the converter for
 
156
            that attribute's type.  Generally, this will be a GetterSetter
 
157
            instance, but it might be something more specific for custom data
 
158
            types (e.g. non-basic types like unicodes).
 
159
        :raises UnknownPATCHRequestError: if the request contains an unknown
 
160
            attribute, i.e. one that is not in the `attributes` mapping.
 
161
        :raises ReadOnlyPATCHRequest: if the requests contains an attribute
 
162
            that is defined as read-only.
 
163
        """
 
164
        validationators = {}
 
165
        for attribute in request.PATCH:
 
166
            if attribute not in converters:
 
167
                raise UnknownPATCHRequestError(attribute)
 
168
            if converters[attribute].decoder is None:
 
169
                raise ReadOnlyPATCHRequestError(attribute)
 
170
            validationators[attribute] = converters[attribute]
 
171
        super(PatchValidator, self).__init__(**validationators)