def post(self): """Return the JSON representation of a new resource created through an HTTP POST call. :returns: ``HTTP 201`` if a resource is properly created :returns: ``HTTP 204`` if the resource already exists: an object with identical primary keys already exists. :returns: ``HTTP 400`` if the request is malformed or missing data """ primary_keys = [ key.name for key in inspect(self.__model__).primary_key ] key_obj = {} for key in primary_keys: if key in request.json: key_obj[key] = request.json[key] if key_obj != {}: resource = self.__model__.query.filter_by(**key_obj).first() if resource: error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) return self._no_content_response() resource = self.__model__(**request.json) # pylint: disable=not-callable error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) db.session().add(resource) db.session().commit() return self._created_response(resource)
def get(self, resource_id=None): """Return an HTTP response object resulting from an HTTP GET call. If *resource_id* is provided, return just the single resource. Otherwise, return the full collection. :param resource_id: The value of the resource's primary key """ if request.path.endswith('meta'): return self._meta() if resource_id is None: error_message = is_valid_method(self.__model__) if error_message: raise BadRequestException(error_message) if 'export' in request.args: return self._export(self._all_resources()) return flask.jsonify( {self.__json_collection_name__: self._all_resources()}) else: resource = self._resource(resource_id) error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) return jsonify(resource)
def put(self, resource_id): """Return the JSON representation of a new resource created or updated through an HTTP PUT call. If resource_id is not provided, it is assumed the primary key field is included and a totally new resource is created. Otherwise, the existing resource referred to by *resource_id* is updated with the provided JSON data. This method is idempotent. :returns: ``HTTP 201`` if a new resource is created :returns: ``HTTP 200`` if a resource is updated :returns: ``HTTP 400`` if the request is malformed or missing data """ resource = self.__model__.query.get(resource_id) if resource: error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) resource.update(request.json) db.session().merge(resource) db.session().commit() return jsonify(resource) resource = self.__model__(**request.json) # pylint: disable=not-callable error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) db.session().add(resource) db.session().commit() return self._created_response(resource)
def prepareYear(self, key, value, backend, filters): """Set year Filter """ key = f"`{key}`" values = value.split(",") if len(values) > 2: if backend == 'sqlite': ftext = f"cast(strftime('%Y',{key}) AS INTEGER) between {values[1]} and {values[2]}" filters.append(text(ftext)) elif backend == 'mysql': ftext = f"year(date({key})) between {values[1]} and {values[2]}" filters.append(text(ftext)) else: raise BadRequestException( 'Invalid backend for Year processing') else: if backend == 'sqlite': ftext = f"cast(strftime('%Y',{key}) AS INTEGER) = {values[1]}" filters.append(text(ftext)) elif backend == 'mysql': ftext = f"year(date({key})) = {values[1]}" filters.append(text(ftext)) else: raise BadRequestException( 'Invalid backend for Year processing')
def prepareDate(self, key, value, backend, filters): """Set Date Filter """ key = f"`{key}`" values = value.split(",") if len(values) > 2: if backend == 'sqlite': ftext = f"date({key}) between date('{values[1]}') and date('{values[2]}')" filters.append(text(ftext)) elif backend == 'mysql': ftext = f"date({key}) between date('{values[1]}') and date('{values[2]}')" filters.append(text(ftext)) else: raise BadRequestException( 'Invalid backend for Date processing') else: if backend == 'sqlite': ftext = f"date({key}) = date('{values[1]}')" filters.append(text(ftext)) elif backend == 'mysql': ftext = f"date({key}) = date('{values[1]}')" filters.append(text(ftext)) else: raise BadRequestException( 'Invalid backend for Date processing')
def decorated(instance, *args, **kwargs): """The decorator function.""" data = request.get_json(force=True, silent=True) if not data: raise BadRequestException('No data received from request') for key in data: if key not in (instance.__model__.required() + instance.__model__.optional()): raise BadRequestException('Unknown field [{}]'.format(key)) for required in set(instance.__model__.required()): if required not in data: raise BadRequestException('[{}] required'.format(required)) return func(instance, *args, **kwargs)
def decorated(instance, *args, **kwargs): """The decorator function.""" data = request.get_json(force=True, silent=True) if not data: raise BadRequestException('No data received from request') for key in data: if key not in (instance.__model__.required() + instance.__model__.optional()): raise BadRequestException('Unknown field [{}]'.format(key)) missing = set(instance.__model__.required()) - set(data) if missing: message = 'The following required fields are missing: ' + ', '.join( missing) raise BadRequestException(message) return func(instance, *args, **kwargs)
def _all_resources(self): """Return the complete collection of resources as a list of dictionaries. :rtype: :class:`sandman2.model.Model` """ queryset = self.__model__.query args = { k: v for (k, v) in request.args.items() if k not in ('page', 'export') } if args: filters = [] order = [] limit = None for key, value in args.items(): if value.startswith('%'): filters.append( getattr(self.__model__, key).like(str(value), escape='/')) elif key == 'sort': order.append(getattr(self.__model__, value)) elif key == 'limit': limit = value elif hasattr(self.__model__, key): filters.append(getattr(self.__model__, key) == value) else: raise BadRequestException('Invalid field [{}]'.format(key)) queryset = queryset.filter(*filters).order_by( *order).limit(limit) if 'page' in request.args: resources = queryset.paginate(int(request.args['page'])).items else: resources = queryset.all() return [r.to_dict() for r in resources]
def get(self, resource_id=None): """Return an HTTP response object resulting from an HTTP GET call. If *resource_id* is provided, return just the single resource. Otherwise, return the full collection. :param resource_id: The value of the resource's primary key """ if request.path.endswith('meta'): return self._meta() if resource_id is None: error_message = is_valid_method(self.__model__) if error_message: raise BadRequestException(error_message) if 'export' in request.args: return self._export(self._all_resources()) if 'collection' in request.args: if 'split' in request.args: # column seen as a date and split into three more fields: year, month, day results = self._all_resources() splits = request.args['split'].split(',') scolumn = splits[0] sformat = splits[1] tr_results = [] for result in results: sdate = str(result[scolumn]) date = datetime.strptime(sdate, sformat) result[scolumn + "_year"] = date.year result[scolumn + "_month"] = date.month result[scolumn + "_day"] = date.day tr_results.append(result) return flask.jsonify(tr_results) else: return flask.jsonify(self._all_resources()) return flask.jsonify( {self.__json_collection_name__: self._all_resources()}) else: resource = self._resource(resource_id) error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) return jsonify(resource)
def _all_resources(self): """Return the complete collection of resources as a list of dictionaries. :rtype: :class:`sandman2.model.Model` """ db.engine.echo = True backend = "" if 'sqlite' in db.engine.name: backend = 'sqlite' elif 'mysql' in db.engine.name: backend = 'mysql' queryset = self.__model__.query args = { k: v for (k, v) in request.args.items() if (k not in ('page', 'export', 'collection', 'split') and not k.isnumeric()) } limit = None if args: filters = [] order = [] for key, value in args.items(): #flask.current_app.logger.debug(value) print(f"{key}={value}", file=sys.stdout, flush=True) if value.startswith('%'): filters.append( getattr(self.__model__, key).like(str(value), escape='/')) elif key == 'sort': direction = desc if value.startswith('-') else asc order.append( direction(getattr(self.__model__, value.lstrip('-')))) elif key == 'limit': limit = int(value) elif hasattr(self.__model__, key): if value.startswith("DATE"): self.prepareDate(key, value, backend, filters) elif value.startswith("YEAR"): self.prepareYear(key, value, backend, filters) elif "|" in value: values = value.split("|") filters.append( getattr(self.__model__, key).in_(values)) else: filters.append(getattr(self.__model__, key) == value) else: raise BadRequestException('Invalid field [{}]'.format(key)) queryset = queryset.filter(*filters).order_by(*order) if 'page' in request.args: resources = queryset.paginate(page=int(request.args['page']), per_page=limit).items else: queryset = queryset.limit(limit) resources = queryset.all() db.engine.echo = False return [r.to_dict() for r in resources]
def patch(self, resource_id): """Return an HTTP response object resulting from an HTTP PATCH call. :returns: ``HTTP 200`` if the resource already exists :returns: ``HTTP 400`` if the request is malformed :returns: ``HTTP 404`` if the resource is not found :param resource_id: The value of the resource's primary key """ resource = self._resource(resource_id) error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) if not request.json: raise BadRequestException('No JSON data received') resource.update(request.json) db.session().merge(resource) db.session().commit() return jsonify(resource)
def delete(self, resource_id): """Return an HTTP response object resulting from a HTTP DELETE call. :param resource_id: The value of the resource's primary key """ resource = self._resource(resource_id) error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) db.session().delete(resource) db.session().commit() return self._no_content_response()
def post(self): """Return the JSON representation of a new resource created through an HTTP POST call. :returns: ``HTTP 201`` if a resource is properly created :returns: ``HTTP 204`` if the resource already exists :returns: ``HTTP 400`` if the request is malformed or missing data """ resource = self.__model__.query.filter_by(**request.json).first() if resource: error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) return self._no_content_response() resource = self.__model__(**request.json) # pylint: disable=not-callable error_message = is_valid_method(self.__model__, resource) if error_message: raise BadRequestException(error_message) db.session().add(resource) db.session().commit() return self._created_response(resource)