コード例 #1
0
        def update_list(update_params):
            final_value = getattr(self, attr, []) or []
            final_value = copy.deepcopy(final_value)
            if update_params is None or update_params == '':
                if not final_value:
                    return
                update_params = ['-' + val for val in final_value]
            if isinstance(update_params, dict):
                keys = list(update_params.keys())
            else:
                keys = update_params

            positive, negative = split_keys(keys)

            if not (positive + negative):
                raise JHTTPBadRequest('Missing params')

            if positive:
                if unique:
                    positive = [v for v in positive if v not in final_value]
                final_value += positive

            if negative:
                final_value = list(set(final_value) - set(negative))

            setattr(self, attr, final_value)
            if save:
                self.save(request)
コード例 #2
0
 def validate(self, *arg, **kw):
     try:
         return super(BaseDocument, self).validate(*arg, **kw)
     except mongo.ValidationError as e:
         raise JHTTPBadRequest('Resource `%s`: %s' %
                               (self.__class__.__name__, e),
                               extra={'data': e})
コード例 #3
0
ファイル: view.py プロジェクト: timgates42/nefertari
        def view_mapper_wrapper(context, request):
            matchdict = request.matchdict.copy()
            matchdict.pop('action', None)
            matchdict.pop('traverse', None)

            # instance of BaseView (or child of)
            view_obj = view(context, request)
            action = getattr(view_obj, action_name)
            request.action = action_name

            # Tunneled collection PATCH/PUT doesn't support query params
            tunneled = getattr(request, '_tunneled_get', False)
            if tunneled and action_name in ('update_many', ):
                view_obj._query_params = dictset()

            # we should not run "after_calls" here, so lets save them in
            # request as filters they will be ran in the renderer factory
            request.filters = view_obj._after_calls

            try:
                # run before_calls (validators) before running the action
                for call in view_obj._before_calls.get(action_name, []):
                    call(request=request)

            except wrappers.ValidationError as e:
                log.error('validation error: %s', e)
                raise JHTTPBadRequest(e.args)

            except wrappers.ResourceNotFound as e:
                log.error('resource not found: %s', e)
                raise JHTTPNotFound()

            trigger_before_events(view_obj)
            return action(**matchdict)
コード例 #4
0
    def apply_fields(cls, query_set, _fields):
        """ Apply fields' restrictions to `query_set`.

        First, fields are split to fields that should only be included and
        fields that should be excluded. Then excluded fields are removed
        from included fields.
        """
        fields_only, fields_exclude = process_fields(_fields)
        if not (fields_only or fields_exclude):
            return query_set
        try:
            fields_only = fields_only or cls.native_fields()
            fields_exclude = fields_exclude or []
            if fields_exclude:
                # Remove fields_exclude from fields_only
                fields_only = [
                    f for f in fields_only if f not in fields_exclude
                ]
            if fields_only:
                # Add PK field
                fields_only.append(cls.pk_field())
                fields_only = [
                    getattr(cls, f) for f in sorted(set(fields_only))
                ]
                query_set = query_set.with_entities(*fields_only)

        except InvalidRequestError as e:
            raise JHTTPBadRequest('Bad _fields param: %s ' % e)

        return query_set
コード例 #5
0
 def check_fields_allowed(cls, fields):
     """ Check if `fields` are allowed to be used on this model. """
     fields = [f.split('__')[0] for f in fields]
     fields_to_query = set(cls.fields_to_query())
     if not set(fields).issubset(fields_to_query):
         not_allowed = set(fields) - fields_to_query
         raise JHTTPBadRequest("'%s' object does not have fields: %s" %
                               (cls.__name__, ', '.join(not_allowed)))
コード例 #6
0
 def get_or_create(cls, **params):
     defaults = params.pop('defaults', {})
     try:
         return cls.objects.get(**params), False
     except mongo.queryset.DoesNotExist:
         defaults.update(params)
         return cls(**defaults).save(), True
     except mongo.queryset.MultipleObjectsReturned:
         raise JHTTPBadRequest('Bad or Insufficient Params')
コード例 #7
0
 def check_fields_allowed(cls, fields):
     if issubclass(cls, mongo.DynamicDocument):
         # Dont check if its dynamic doc
         return
     fields = [f.split('__')[0] for f in fields]
     fields_to_query = set(cls.fields_to_query())
     if not set(fields).issubset(fields_to_query):
         not_allowed = set(fields) - fields_to_query
         raise JHTTPBadRequest("'%s' object does not have fields: %s" %
                               (cls.__name__, ', '.join(not_allowed)))
コード例 #8
0
ファイル: view.py プロジェクト: timgates42/nefertari
        def _get_object(id_):
            if hasattr(id_, 'pk_field'):
                return id_

            obj = model.get_item(**{pk_field: id_, '_raise_on_empty': False})
            if setdefault:
                return obj or setdefault
            else:
                if not obj:
                    raise JHTTPBadRequest('id2obj: Object %s not found' % id_)
                return obj
コード例 #9
0
ファイル: models.py プロジェクト: timgates42/nefertari
    def create_account(cls, params):
        """ Create auth user instance with data from :params:.

        Used by both Token and Ticket-based auths to register a user (
        called from views).
        """
        user_params = dictset(params).subset(['username', 'email', 'password'])
        try:
            return cls.get_or_create(email=user_params['email'],
                                     defaults=user_params)
        except JHTTPBadRequest:
            raise JHTTPBadRequest('Failed to create account.')
コード例 #10
0
    def apply_fields(cls, query_set, _fields):
        fields_only, fields_exclude = process_fields(_fields)

        try:
            if fields_only:
                query_set = query_set.only(*fields_only)

            if fields_exclude:
                query_set = query_set.exclude(*fields_exclude)

        except mongo.InvalidQueryError as e:
            raise JHTTPBadRequest('Bad _fields param: %s ' % e)

        return query_set
コード例 #11
0
        def update_list():
            pos_keys, neg_keys = split_keys(params.keys())

            if not (pos_keys + neg_keys):
                raise JHTTPBadRequest('missing params')

            if pos_keys:
                if unique:
                    self.update({'add_to_set__%s' % attr: pos_keys})
                else:
                    self.update({'push_all__%s' % attr: pos_keys})

            if neg_keys:
                self.update({'pull_all__%s' % attr: neg_keys})
コード例 #12
0
 def get_or_create(cls, **params):
     defaults = params.pop('defaults', {})
     _limit = params.pop('_limit', 1)
     query_set = cls.get_collection(_limit=_limit, **params)
     try:
         obj = query_set.one()
         return obj, False
     except NoResultFound:
         defaults.update(params)
         new_obj = cls(**defaults)
         new_obj.save()
         return new_obj, True
     except MultipleResultsFound:
         raise JHTTPBadRequest('Bad or Insufficient Params')
コード例 #13
0
    def register(self):
        """ Register a new user by POSTing all required data.

        User's `Authorization` header value is returned in `WWW-Authenticate`
        header.
        """
        user, created = self.Model.create_account(self._json_params)
        if user.api_key is None:
            raise JHTTPBadRequest('Failed to generate ApiKey for user')

        if not created:
            raise JHTTPConflict('Looks like you already have an account.')

        self.request._user = user
        headers = remember(self.request, user.username)
        return JHTTPOk('Registered', headers=headers)
コード例 #14
0
ファイル: documents.py プロジェクト: oleduc/nefertari-sqla
        def update_list(update_params):
            final_value = getattr(self, attr) or []
            final_value = copy.deepcopy(final_value)

            if update_params is None or update_params == '':
                if not final_value:
                    return
                update_params = ['-' + val for val in final_value]
            if isinstance(update_params, dict):
                keys = list(update_params.keys())
            else:
                keys = update_params

            positives, negatives = split_keys(keys)

            if not positives and not negatives:
                raise JHTTPBadRequest('Missing params')

            parameters = {}
            cls_name = self.__class__.__name__
            location_dot_notation = "\"" + cls_name.lower() + "\"" + "." + attr
            sql_expression = location_dot_notation

            for index, negative in enumerate(negatives):
                index_str = str(index)

                if sql_expression == location_dot_notation:
                    sql_expression = "array_remove(" + location_dot_notation + ", :negative_" + index_str + ")"
                else:
                    sql_expression = "array_remove(" + sql_expression + ", :negative_" + index_str + ")"

                parameters["negative_" + index_str] = negative

            if len(positives) > 0:
                sql_expression = "array_cat(" + sql_expression + ", :added_items)"
                parameters["added_items"] = list(
                    set(positives) - set(final_value))

            expression = text(sql_expression).bindparams(**parameters)
            setattr(self, attr, expression)

            object_session(self).flush()

            if save:
                self.save()
コード例 #15
0
def set_public_limits(view):
    public_max = int(
        view.request.registry.settings.get('public_max_limit', 100))

    try:
        _limit = int(view._params.get('_limit', 20))
        _page = int(view._params.get('_page', 0))
        _start = int(view._params.get('_start', 0))

        view.add_after_call('index',
                            set_total(view.request, total=public_max),
                            pos=0)
    except ValueError:
        from nefertari.json_httpexceptions import JHTTPBadRequest
        raise JHTTPBadRequest("Bad _limit/_page param")

    _start = _start or _page * _limit
    if _start + _limit > public_max:
        view._params['_limit'] = max((public_max - _start), 0)
コード例 #16
0
ファイル: view.py プロジェクト: timgates42/nefertari
def error_view(context, request):
    return JHTTPBadRequest(context.args[0])
コード例 #17
0
ファイル: view.py プロジェクト: timgates42/nefertari
def value_error_view(context, request):
    return JHTTPBadRequest("Bad or missing value '%s'" % context.args[0])
コード例 #18
0
ファイル: view.py プロジェクト: timgates42/nefertari
def key_error_view(context, request):
    return JHTTPBadRequest("Bad or missing param '%s'" % context.args[0])
コード例 #19
0
    def get_collection(cls, **params):
        """
        params may include '_limit', '_page', '_sort', '_fields'
        returns paginated and sorted query set
        raises JHTTPBadRequest for bad values in params
        """
        params.pop('__confirmation', False)
        __strict = params.pop('__strict', True)

        _sort = _split(params.pop('_sort', []))
        _fields = _split(params.pop('_fields', []))
        _limit = params.pop('_limit', None)
        _page = params.pop('_page', None)
        _start = params.pop('_start', None)

        _count = '_count' in params
        params.pop('_count', None)
        _explain = '_explain' in params
        params.pop('_explain', None)
        __raise_on_empty = params.pop('__raise_on_empty', False)

        query_set = cls.objects

        # Remove any __ legacy instructions from this point on
        params = dictset(
            filter(lambda item: not item[0].startswith('__'), params.items()))

        if __strict:
            _check_fields = [
                f.strip('-+') for f in params.keys() + _fields + _sort
            ]
            cls.check_fields_allowed(_check_fields)
        else:
            params = cls.filter_fields(params)

        process_lists(params)
        process_bools(params)

        #if param is _all then remove it
        params.pop_by_values('_all')

        try:
            query_set = query_set(**params)
            _total = query_set.count()
            if _count:
                return _total

            if _limit is None:
                raise JHTTPBadRequest('Missing _limit')

            _start, _limit = process_limit(_start, _page, _limit)

            # Filtering by fields has to be the first thing to do on the query_set!
            query_set = cls.apply_fields(query_set, _fields)
            query_set = cls.apply_sort(query_set, _sort)
            query_set = query_set[_start:_start + _limit]

            if not query_set.count():
                msg = "'%s(%s)' resource not found" % (cls.__name__, params)
                if __raise_on_empty:
                    raise JHTTPNotFound(msg)
                else:
                    log.debug(msg)

        except (mongo.ValidationError, mongo.InvalidQueryError) as e:
            raise JHTTPBadRequest(str(e), extra={'data': e})

        if _explain:
            return query_set.explain()

        log.debug('get_collection.query_set: %s(%s)', cls.__name__,
                  query_set._query)

        query_set._nefertari_meta = dict(total=_total,
                                         start=_start,
                                         fields=_fields)

        return query_set
コード例 #20
0
    def get_collection(cls, **params):
        """ Query collection and return results.

        Notes:
        *   Before validating that only model fields are present in params,
            reserved params, query params and all params starting with
            double underscore are dropped.
        *   Params which have value "_all" are dropped.
        *   When ``_count`` param is used, objects count is returned
            before applying offset and limit.

        :param bool _strict: If True ``params`` are validated to contain
            only fields defined on model, exception is raised if invalid
            fields are present. When False - invalid fields are dropped.
            Defaults to ``True``.
        :param bool _item_request: Indicates whether it is a single item
            request or not. When True and DataError happens on DB request,
            JHTTPNotFound is raised. JHTTPBadRequest is raised when False.
            Defaults to ``False``.
        :param list _sort: Field names to sort results by. If field name
            is prefixed with "-" it is used for "descending" sorting.
            Otherwise "ascending" sorting is performed by that field.
            Defaults to an empty list in which case sorting is not
            performed.
        :param list _fields: Names of fields which should be included
            or excluded from results. Fields to excluded should be
            prefixed with "-". Defaults to an empty list in which
            case all fields are returned.
        :param int _limit: Number of results per page. Defaults
            to None in which case all results are returned.
        :param int _page: Number of page. In conjunction with
            ``_limit`` is used to calculate results offset. Defaults to
            None in which case it is ignored. Params ``_page`` and
            ``_start` are mutually exclusive.
        :param int _start: Results offset. If provided ``_limit`` and
            ``_page`` params are ignored when calculating offset. Defaults
            to None. Params ``_page`` and ``_start`` are mutually
            exclusive. If not offset-related params are provided, offset
            equals to 0.
        :param Query query_set: Existing queryset. If provided, all queries
            are applied to it instead of creating new queryset. Defaults
            to None.
        :param _count: When provided, only results number is returned as
            integer.
        :param _explain: When provided, query performed(SQL) is returned
            as a string instead of query results.
        :param bool _raise_on_empty: When True JHTTPNotFound is raised
            if query returned no results. Defaults to False in which case
            error is just logged and empty query results are returned.

        :returns: Query results as ``sqlalchemy.orm.query.Query`` instance.
            May be sorted, offset, limited.
        :returns: Dict of {'field_name': fieldval}, when ``_fields`` param
            is provided.
        :returns: Number of query results as an int when ``_count`` param
            is provided.
        :returns: String representing query ran when ``_explain`` param
            is provided.

        :raises JHTTPNotFound: When ``_raise_on_empty=True`` and no
            results found.
        :raises JHTTPNotFound: When ``_item_request=True`` and
            ``sqlalchemy.exc.DataError`` exception is raised during DB
            query. Latter exception is raised when querying DB with
            an identifier of a wrong type. E.g. when querying Int field
            with a string.
        :raises JHTTPBadRequest: When ``_item_request=False`` and
            ``sqlalchemy.exc.DataError`` exception is raised during DB
            query.
        :raises JHTTPBadRequest: When ``sqlalchemy.exc.InvalidRequestError``
            or ``sqlalchemy.exc.IntegrityError`` errors happen during DB
            query.
        """
        log.debug('Get collection: {}, {}'.format(cls.__name__, params))
        params.pop('__confirmation', False)
        _strict = params.pop('_strict', True)
        _item_request = params.pop('_item_request', False)

        _sort = _split(params.pop('_sort', []))
        _fields = _split(params.pop('_fields', []))
        _limit = params.pop('_limit', None)
        _page = params.pop('_page', None)
        _start = params.pop('_start', None)
        query_set = params.pop('query_set', None)

        _count = '_count' in params
        params.pop('_count', None)
        _explain = '_explain' in params
        params.pop('_explain', None)
        _raise_on_empty = params.pop('_raise_on_empty', False)

        if query_set is None:
            query_set = Session().query(cls)

        # Remove any __ legacy instructions from this point on
        params = dictset({
            key: val
            for key, val in params.items() if not key.startswith('__')
        })

        iterables_exprs, params = cls._pop_iterables(params)

        params = drop_reserved_params(params)
        if _strict:
            _check_fields = [
                f.strip('-+') for f in list(params.keys()) + _fields + _sort
            ]
            cls.check_fields_allowed(_check_fields)
        else:
            params = cls.filter_fields(params)

        process_lists(params)
        process_bools(params)

        # If param is _all then remove it
        params.pop_by_values('_all')

        try:

            query_set = query_set.filter_by(**params)

            # Apply filtering by iterable expressions
            for expr in iterables_exprs:
                query_set = query_set.from_self().filter(expr)

            _total = query_set.count()
            if _count:
                return _total

            # Filtering by fields has to be the first thing to do on
            # the query_set!
            query_set = cls.apply_fields(query_set, _fields)
            query_set = cls.apply_sort(query_set, _sort)

            if _limit is not None:
                _start, _limit = process_limit(_start, _page, _limit)
                query_set = query_set.offset(_start).limit(_limit)

            if not query_set.count():
                msg = "'%s(%s)' resource not found" % (cls.__name__, params)
                if _raise_on_empty:
                    raise JHTTPNotFound(msg)
                else:
                    log.debug(msg)

        except DataError as ex:
            if _item_request:
                msg = "'{}({})' resource not found".format(
                    cls.__name__, params)
                raise JHTTPNotFound(msg, explanation=ex.message)
            else:
                raise JHTTPBadRequest(str(ex), extra={'data': ex})
        except (InvalidRequestError, ) as ex:
            raise JHTTPBadRequest(str(ex), extra={'data': ex})

        query_sql = str(query_set).replace('\n', '')
        if _explain:
            return query_sql

        log.debug('get_collection.query_set: %s (%s)', cls.__name__, query_sql)

        if _fields:
            query_set = cls.add_field_names(query_set, _fields)

        query_set._nefertari_meta = dict(total=_total,
                                         start=_start,
                                         fields=_fields)
        return query_set