Ejemplo n.º 1
0
class GeocodeParameters(Parameters):
    """
    Helper Parameters class to reuse geocoding.
    """
    search = base_fields.String(
        description="the type of query we want to search",
    )
    filters = base_fields.Raw()
    coordinates = base_fields.List(
        cls_or_instance=base_fields.List(
            cls_or_instance=base_fields.Float()
        ),
        allow_none=True,
    )
    latitude = base_fields.Float(
        allow_none=True,
        description="the latitude to search in",
        validate=validate.Range(min=-90.0, max=90.0, error="Invalid latitude parameters. Must be between -90 and 90.")
    )
    longitude = base_fields.Float(
        allow_none=True,
        description="the latitude to search in",
        validate=validate.Range(min=-180.0, max=180.0,
                                error="Invalid longitude parameters. Must be between -180 and 180.")
    )
    radius = base_fields.Float(
        description="the radius to search in",
        missing=5,
        validate=validate.Range(min=0)
    )
Ejemplo n.º 2
0
class BasicPagerSchema(ModelSchema):
    has_prev = base_fields.Boolean() 
    has_next = base_fields.Boolean() 
    pages = base_fields.Integer() 
    page = base_fields.Integer() 
    lst_size = base_fields.Integer()
    total = base_fields.Integer() 
    items = base_fields.Raw()
    class Meta:
        pass
class PatchJSONParameters(Parameters):
    """
    Base parameters class for handling PATCH arguments according to RFC 6902.
    """

    # All operations described in RFC 6902
    OP_ADD = 'add'
    OP_REMOVE = 'remove'
    OP_REPLACE = 'replace'
    OP_MOVE = 'move'
    OP_COPY = 'copy'
    OP_TEST = 'test'

    # However, we use only those which make sense in RESTful API
    OPERATION_CHOICES = (
        OP_TEST,
        OP_ADD,
        OP_REMOVE,
        OP_REPLACE,
    )
    op = base_fields.String(required=True)  # pylint: disable=invalid-name

    PATH_CHOICES = None
    path = base_fields.String(required=True)

    value = base_fields.Raw(required=False)

    def __init__(self, *args, **kwargs):
        super(PatchJSONParameters, self).__init__(*args, many=True, **kwargs)
        if not self.PATH_CHOICES:
            raise ValueError("%s.PATH_CHOICES has to be set" %
                             self.__class__.__name__)
        # Make a copy of `validators` as otherwise we will modify the behaviour
        # of all `marshmallow.Schema`-based classes
        self.fields['op'].validators = \
            self.fields['op'].validators + [validate.OneOf(self.OPERATION_CHOICES)]
        self.fields['path'].validators = \
            self.fields['path'].validators + [validate.OneOf(self.PATH_CHOICES)]
Ejemplo n.º 4
0
class PatchJSONParameters(Parameters):
    """
    Base parameters class for handling PATCH arguments according to RFC 6902.
    """

    # All operations described in RFC 6902
    OP_ADD = 'add'
    OP_REMOVE = 'remove'
    OP_REPLACE = 'replace'
    OP_MOVE = 'move'
    OP_COPY = 'copy'
    OP_TEST = 'test'

    # However, we use only those which make sense in RESTful API
    OPERATION_CHOICES = (
        OP_TEST,
        OP_ADD,
        OP_REMOVE,
        OP_REPLACE,
    )
    op = base_fields.String(required=True)  # pylint: disable=invalid-name

    PATH_CHOICES = None

    path = base_fields.String(required=True)

    NO_VALUE_OPERATIONS = (OP_REMOVE,)

    value = base_fields.Raw(required=False)

    def __init__(self, *args, **kwargs):
        if 'many' in kwargs:
            assert kwargs['many'], "PATCH Parameters must be marked as 'many'"
        kwargs['many'] = True
        super(PatchJSONParameters, self).__init__(*args, **kwargs)
        if not self.PATH_CHOICES:
            raise ValueError('%s.PATH_CHOICES has to be set' % self.__class__.__name__)
        # Make a copy of `validators` as otherwise we will modify the behaviour
        # of all `marshmallow.Schema`-based classes
        self.fields['op'].validators = self.fields['op'].validators + [
            validate.OneOf(self.OPERATION_CHOICES)
        ]
        self.fields['path'].validators = self.fields['path'].validators + [
            validate.OneOf(self.PATH_CHOICES)
        ]

    @validates_schema
    def validate_patch_structure(self, data):
        """
        Common validation of PATCH structure

        Provide check that 'value' present in all operations expect it.

        Provide check if 'path' is present. 'path' can be absent if provided
        without '/' at the start. Supposed that if 'path' is present than it
        is prepended with '/'.
        Removing '/' in the beginning to simplify usage in resource.
        """
        if data['op'] not in self.NO_VALUE_OPERATIONS and 'value' not in data:
            raise ValidationError('value is required')

        if 'path' not in data:
            raise ValidationError('Path is required and must always begin with /')
        else:
            data['field_name'] = data['path'][1:]

    @classmethod
    def perform_patch(cls, operations, obj, state=None):
        """
        Performs all necessary operations by calling class methods with
        corresponding names.
        """
        if state is None:
            state = {}
        for operation in operations:
            if not cls._process_patch_operation(operation, obj=obj, state=state):
                log.info(
                    '%s patching has been stopped because of unknown operation %s',
                    obj.__class__.__name__,
                    operation,
                )
                raise ValidationError(
                    'Failed to update %s details. Operation %s could not succeed.'
                    % (obj.__class__.__name__, operation)
                )
        return True

    @classmethod
    def _process_patch_operation(cls, operation, obj, state):
        """
        Args:
            operation (dict): one patch operation in RFC 6902 format.
            obj (object): an instance which is needed to be patched.
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True if operation was handled, otherwise False.
        """
        field_operaion = operation['op']

        if field_operaion == cls.OP_REPLACE:
            return cls.replace(
                obj, operation['field_name'], operation['value'], state=state
            )

        elif field_operaion == cls.OP_TEST:
            return cls.test(obj, operation['field_name'], operation['value'], state=state)

        elif field_operaion == cls.OP_ADD:
            return cls.add(obj, operation['field_name'], operation['value'], state=state)

        elif field_operaion == cls.OP_MOVE:
            return cls.move(obj, operation['field_name'], operation['value'], state=state)

        elif field_operaion == cls.OP_COPY:
            return cls.copy(obj, operation['field_name'], operation['value'], state=state)

        elif field_operaion == cls.OP_REMOVE:
            # This deviates from RFC 6902 to permit field and value based removal.
            # This is used for multiple relationship tables within houston
            return cls.remove(
                obj, operation['field_name'], operation.get('value', None), state=state
            )

        return False

    @classmethod
    def replace(cls, obj, field, value, state):
        """
        This is method for replace operation. It is separated to provide a
        possibility to easily override it in your Parameters.

        Args:
            obj (object): an instance to change.
            field (str): field name
            value (str): new value
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True
        """
        # Check for existence
        if not hasattr(obj, field):
            raise ValidationError(
                "Field '%s' does not exist, so it cannot be patched" % field
            )
        # Check for Enum objects
        try:
            obj_cls = obj.__class__
            obj_column = getattr(obj_cls, field)
            obj_column_type = obj_column.expression.type
            if isinstance(obj_column_type, sa.sql.sqltypes.Enum):
                enum_values = obj_column_type.enums
                if value not in enum_values:
                    args = (field, value, enum_values)
                    raise ValidationError(
                        "Field '%s' is an Enum and does not recognize the value '%s'.  Please select one of %r"
                        % args
                    )
        except (AttributeError):
            pass
        # Set the value
        setattr(obj, field, value)
        return True

    @classmethod
    def test(cls, obj, field, value, state):
        """
        This is method for test operation. It is separated to provide a
        possibility to easily override it in your Parameters.

        Args:
            obj (object): an instance to change.
            field (str): field name
            value (str): new value
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True
        """
        return getattr(obj, field) == value

    @classmethod
    def add(cls, obj, field, value, state):
        raise NotImplementedError()

    @classmethod
    def remove(cls, obj, field, value, state):
        """
        This is method for removal operation. It is separated to provide a
        possibility to easily override it in your Parameters.

        Args:
            obj (object): an instance to change.
            field (str): field name
            value (str): [optional] item to remove for lists, Extension on RFC 6509
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True
        """
        raise NotImplementedError()

    @classmethod
    def move(cls, obj, field, value, state):
        raise NotImplementedError()

    @classmethod
    def copy(cls, obj, field, value, state):
        raise NotImplementedError()
Ejemplo n.º 5
0
class PatchJSONParameters(Parameters):
    """
    Base parameters class for handling PATCH arguments according to RFC 6902.
    """

    # All operations described in RFC 6902
    OP_ADD = "add"
    OP_REMOVE = "remove"
    OP_REPLACE = "replace"
    OP_MOVE = "move"
    OP_COPY = "copy"
    OP_TEST = "test"

    # However, we use only those which make sense in RESTful API
    OPERATION_CHOICES = (
        OP_TEST,
        OP_ADD,
        OP_REMOVE,
        OP_REPLACE,
    )
    op = base_fields.String(required=True)  # pylint: disable=invalid-name

    PATH_CHOICES = None

    path = base_fields.String(required=True)

    NO_VALUE_OPERATIONS = (OP_REMOVE, )

    value = base_fields.Raw(required=False)

    def __init__(self, *args, **kwargs):
        if "many" in kwargs:
            assert kwargs["many"], "PATCH Parameters must be marked as 'many'"
        kwargs["many"] = True
        super(PatchJSONParameters, self).__init__(*args, **kwargs)
        if not self.PATH_CHOICES:
            raise ValueError("%s.PATH_CHOICES has to be set" %
                             self.__class__.__name__)
        # Make a copy of `validators` as otherwise we will modify the behaviour
        # of all `marshmallow.Schema`-based classes
        self.fields["op"].validators = self.fields["op"].validators + [
            validate.OneOf(self.OPERATION_CHOICES)
        ]
        self.fields["path"].validators = self.fields["path"].validators + [
            validate.OneOf(self.PATH_CHOICES)
        ]

    @validates_schema
    def validate_patch_structure(self, data):
        """
        Common validation of PATCH structure

        Provide check that 'value' present in all operations expect it.

        Provide check if 'path' is present. 'path' can be absent if provided
        without '/' at the start. Supposed that if 'path' is present than it
        is prepended with '/'.
        Removing '/' in the beginning to simplify usage in resource.
        """
        if data["op"] not in self.NO_VALUE_OPERATIONS and "value" not in data:
            raise ValidationError("value is required")

        if "path" not in data:
            raise ValidationError(
                "Path is required and must always begin with /")
        else:
            data["field_name"] = data["path"][1:]

    @classmethod
    def perform_patch(cls, operations, obj, state=None):
        """
        Performs all necessary operations by calling class methods with
        corresponding names.
        """
        if state is None:
            state = {}
        for operation in operations:
            if not cls._process_patch_operation(
                    operation, obj=obj, state=state):
                log.info(
                    "%s patching has been stopped because of unknown operation %s",
                    obj.__class__.__name__,
                    operation,
                )
                raise ValidationError(
                    "Failed to update %s details. Operation %s could not succeed."
                    % (obj.__class__.__name__, operation))
        return True

    @classmethod
    def _process_patch_operation(cls, operation, obj, state):
        """
        Args:
            operation (dict): one patch operation in RFC 6902 format.
            obj (object): an instance which is needed to be patched.
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True if operation was handled, otherwise False.
        """
        field_operaion = operation["op"]

        if field_operaion == cls.OP_REPLACE:
            return cls.replace(obj,
                               operation["field_name"],
                               operation["value"],
                               state=state)

        elif field_operaion == cls.OP_TEST:
            return cls.test(obj,
                            operation["field_name"],
                            operation["value"],
                            state=state)

        elif field_operaion == cls.OP_ADD:
            return cls.add(obj,
                           operation["field_name"],
                           operation["value"],
                           state=state)

        elif field_operaion == cls.OP_MOVE:
            return cls.move(obj,
                            operation["field_name"],
                            operation["value"],
                            state=state)

        elif field_operaion == cls.OP_COPY:
            return cls.copy(obj,
                            operation["field_name"],
                            operation["value"],
                            state=state)

        elif field_operaion == cls.OP_REMOVE:
            return cls.remove(obj, operation["field_name"], state=state)

        return False

    @classmethod
    def replace(cls, obj, field, value, state):
        """
        This is method for replace operation. It is separated to provide a
        possibility to easily override it in your Parameters.

        Args:
            obj (object): an instance to change.
            field (str): field name
            value (str): new value
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True
        """
        if not hasattr(obj, field):
            raise ValidationError(
                "Field '%s' does not exist, so it cannot be patched" % field)
        setattr(obj, field, value)
        return True

    @classmethod
    def test(cls, obj, field, value, state):
        """
        This is method for test operation. It is separated to provide a
        possibility to easily override it in your Parameters.

        Args:
            obj (object): an instance to change.
            field (str): field name
            value (str): new value
            state (dict): inter-operations state storage

        Returns:
            processing_status (bool): True
        """
        return getattr(obj, field) == value

    @classmethod
    def add(cls, obj, field, value, state):
        raise NotImplementedError()

    @classmethod
    def remove(cls, obj, field, state):
        raise NotImplementedError()

    @classmethod
    def move(cls, obj, field, value, state):
        raise NotImplementedError()

    @classmethod
    def copy(cls, obj, field, value, state):
        raise NotImplementedError()
Ejemplo n.º 6
0
class BasicSchema(ModelSchema):
    status = base_fields.Integer(default=Status.SUCCESS.status) 
    message = base_fields.String(default=Status.SUCCESS.message) 
    data = base_fields.Raw()
    class Meta:
        pass