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
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
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
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
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
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")