Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #4
0
 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')
Exemple #5
0
 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')
Exemple #6
0
 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)
Exemple #8
0
    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]
Exemple #9
0
    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)
Exemple #10
0
    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]
Exemple #11
0
    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)
Exemple #12
0
    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()
Exemple #13
0
    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)