Example #1
0
    def _get_validated_json_payload(self, related_type_) -> dict:
        """
        Extracting json and validating its fields
        :return:
        """
        json_data = request.json or {}

        if "data" not in json_data:
            raise BadRequest('You must provide data with a "data" route node', source={"pointer": "/data"})
        if isinstance(json_data["data"], dict):
            if "type" not in json_data["data"]:
                raise BadRequest('Missing type in "data" node', source={"pointer": "/data/type"})
            if "id" not in json_data["data"]:
                raise BadRequest('Missing id in "data" node', source={"pointer": "/data/id"})
            if json_data["data"]["type"] != related_type_:
                raise InvalidType("The type field does not match the resource type", source={"pointer": "/data/type"})
        if isinstance(json_data["data"], list):
            for obj in json_data["data"]:
                if "type" not in obj:
                    raise BadRequest('Missing type in "data" node', source={"pointer": "/data/type"})
                if "id" not in obj:
                    raise BadRequest('Missing id in "data" node', source={"pointer": "/data/id"})
                if obj["type"] != related_type_:
                    raise InvalidType(
                        "The type provided does not match the resource type", source={"pointer": "/data/type"}
                    )

        return json_data
Example #2
0
    def pagination(self):
        """Return parameters page[size] and page[number) as a dict.
        If missing parmeter `size` then default parameter PAGE_SIZE is used.

        :return dict: a dict of pagination information

        Example with number strategy::

            >>> query_string = {'page[number]': '25', 'page[size]': '10'}
            >>> parsed_query.pagination
            {'number': 25, 'size': 10}
        """
        # check values type
        result = self._get_key_values('page')
        for key, value in result.items():
            if key not in ('number', 'size'):
                raise BadRequest("{} is not a valid parameter of pagination".format(key), source={'parameter': 'page'})
            try:
                result[key] = int(value)
            except ValueError:
                raise BadRequest("Parse error", source={'parameter': 'page[{}]'.format(key)})

        result.setdefault('size', current_app.config.get('PAGE_SIZE', 30))

        if current_app.config.get('ALLOW_DISABLE_PAGINATION', True) is False and result.get('size') == 0:
            raise BadRequest("You are not allowed to disable pagination", source={'parameter': 'page[size]'})

        if current_app.config.get('MAX_PAGE_SIZE') is not None and 'size' in result:
            if int(result['size']) > current_app.config['MAX_PAGE_SIZE']:
                raise BadRequest("Maximum page size is {}".format(current_app.config['MAX_PAGE_SIZE']),
                                 source={'parameter': 'page[size]'})

        return result
Example #3
0
    def patch(self, *args, **kwargs):
        """Update an object"""
        json_data = request.json or {}

        qs = self.qs_manager_class(request.args, self.schema)
        schema_kwargs = getattr(self, "patch_schema_kwargs", dict())
        schema_kwargs.update({"partial": True})

        self.before_marshmallow(args, kwargs)

        schema = compute_schema(self.schema, schema_kwargs, qs, qs.include)

        for i_plugins in self.plugins:
            try:
                i_plugins.after_init_schema_in_resource_detail_patch(
                    *args,
                    schema=schema,
                    model=self.data_layer["model"],
                    **kwargs)
            except PluginMethodNotImplementedError:
                pass

        if "data" not in json_data:
            raise BadRequest('Missing "data" node',
                             source={"pointer": "/data"})
        if "id" not in json_data["data"]:
            raise BadRequest('Missing id in "data" node',
                             source={"pointer": "/data/id"})
        if str(json_data["data"]["id"]) != str(kwargs[getattr(
                self._data_layer, "url_field", "id")]):
            raise BadRequest(
                "Value of id does not match the resource identifier in url",
                source={"pointer": "/data/id"})

        try:
            data = schema.load(json_data)
        except IncorrectTypeError as e:
            errors = e.messages
            for error in errors["errors"]:
                error["status"] = "409"
                error["title"] = "Incorrect type"
            return errors, 409
        except ValidationError as e:
            errors = e.messages
            for message in errors["errors"]:
                message["status"] = "422"
                message["title"] = "Validation error"
            return errors, 422

        self.before_patch(args, kwargs, data=data)

        obj = self.update_object(data, qs, kwargs)

        result = schema.dump(obj)

        final_result = self.after_patch(result)

        return final_result
Example #4
0
    def _get_key_values(self, name):
        """Return a dict containing key / values items for a given key, used for items like filters, page, etc.

        :param str name: name of the querystring parameter
        :return dict: a dict of key / values items
        """
        results = {}

        for key, value in self.qs.items():
            try:
                if not key.startswith(name):
                    continue

                key_start = key.index('[') + 1
                key_end = key.index(']')
                item_key = key[key_start:key_end]

                if ',' in value:
                    item_value = value.split(',')
                else:
                    item_value = value
                results.update({item_key: item_value})
            except Exception:
                raise BadRequest("Parse error", source={'parameter': key})

        return results
Example #5
0
    def pagination(self):
        """Return all page parameters as a dict.

        :return dict: a dict of pagination information

        To allow multiples strategies, all parameters starting with `page` will be included. e.g::

            {
                "number": '25',
                "size": '150',
            }

        Example with number strategy::

            >>> query_string = {'page[number]': '25', 'page[size]': '10'}
            >>> parsed_query.pagination
            {'number': '25', 'size': '10'}
        """
        # check values type
        result = self._get_key_values('page')
        for key, value in result.items():
            if key not in ('number', 'size'):
                raise BadRequest(
                    "{} is not a valid parameter of pagination".format(key),
                    source={'parameter': 'page'})
            try:
                int(value)
            except ValueError:
                raise BadRequest("Parse error",
                                 source={'parameter': 'page[{}]'.format(key)})

        if current_app.config.get(
                'ALLOW_DISABLE_PAGINATION', True) is False and int(
                    result.get('size', 1)) == 0:
            raise BadRequest("You are not allowed to disable pagination",
                             source={'parameter': 'page[size]'})

        if current_app.config.get(
                'MAX_PAGE_SIZE') is not None and 'size' in result:
            if int(result['size']) > current_app.config['MAX_PAGE_SIZE']:
                raise BadRequest("Maximum page size is {}".format(
                    current_app.config['MAX_PAGE_SIZE']),
                                 source={'parameter': 'page[size]'})

        return result
Example #6
0
    def event_update_avatar(self, *args, id: int = None, **view_kwargs):
        # language=YAML
        """
        ---
        summary: Update user's avatar
        tags:
        - User
        parameters:
        - in: path
          name: id
          required: True
          type: integer
          format: int32
          description: "user's id"
        requestBody:
          content:
            multipart/form-data:
              schema:
                type: object
                properties:
                  new_avatar:
                    type: string
                    format: binary
        consumes:
        - multipart/form-data
        responses:
          201:
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    avatar_url:
                      type: string
                      example: "uploads/avatar.gif"
        """
        avatar = request.files.get("new_avatar")
        if not avatar:
            raise BadRequest(
                "avatar file is required! please fill `new_avatar` form field")

        user = User.query.filter_by(id=id).one_or_none()
        if user is None:
            raise ObjectNotFound(
                "User #{} not found".format(id),
                source={"parameter": "id"},
            )

        filename = avatar.filename
        avatar_path = str(UPLOADS_DIR / filename)
        avatar.save(avatar_path)
        user.avatar_path = str(UPLOADS_DIR_NAME / filename)
        db.session.commit()
        return {"avatar_url": user.avatar_path}, 201
 def _resource_method_bad_request(cls, *args, **kwargs):
     raise BadRequest("No method")