Esempio n. 1
0
    def get(self, *args, **kwargs):
        """Get item details
        """
        try:
            item = self.data_layer.get_item(**kwargs)
        except EntityNotFound as e:
            return ErrorFormatter.format_error([e.message]), e.status_code

        qs = QSManager(request.args)

        schema_kwargs = self.schema.get('get_kwargs', {})
        if qs.fields.get(self.resource_type):
            if schema_kwargs.get('only'):
                schema_kwargs['only'] = tuple(
                    set(schema_kwargs['only'])
                    & set(self.schema['cls']._declared_fields.keys())
                    & set(qs.fields[self.resource_type]))
            else:
                schema_kwargs['only'] = tuple(
                    set(self.schema['cls']._declared_fields.keys())
                    & set(qs.fields[self.resource_type]))
        if schema_kwargs.get('only') and 'id' not in schema_kwargs['only']:
            schema_kwargs['only'] += ('id', )
        schema = self.schema['cls'](**schema_kwargs)

        result = schema.dump(item)

        return result.data
 def get(self, *args, **kwargs):
     qs = QSManager(request.args, self.schema)
     popular_locations = (
         db.session.query(
             Event.searchable_location_name, func.count(Event.id).label('counts')
         )
         .group_by(Event.searchable_location_name)
         .order_by(desc('counts'))
         .limit(6)
     )
     locations = []
     for location, _ in popular_locations:
         if location is not None:
             new_location = EventLocation(name=location)
             new_location.id = len(locations)
             locations.append(new_location)
     schema = EventLocationSchema()
     result = schema.dump(locations, many=True).data
     view_kwargs = (
         request.view_args if getattr(self, 'view_kwargs', None) is True else {}
     )
     add_pagination_links(
         result, len(locations), qs, url_for(self.view, **view_kwargs)
     )
     result.update({'meta': {'count': len(locations)}})
     return result
Esempio n. 3
0
    def get(self, *args, **kwargs):
        """Get a relationship details
        """
        relationship_field, related_type_, related_id_field = self._get_relationship_data()
        related_view = self.schema._declared_fields[relationship_field].related_view
        related_view_kwargs = self.schema._declared_fields[relationship_field].related_view_kwargs

        obj, data = self.data_layer.get_relationship(relationship_field, related_type_, related_id_field, **kwargs)

        for key, value in copy(related_view_kwargs).items():
            if isinstance(value, str) and value.startswith('<') and value.endswith('>'):
                tmp_obj = obj
                for field in value[1:-1].split('.'):
                    tmp_obj = getattr(tmp_obj, field)
                related_view_kwargs[key] = tmp_obj

        result = {'links': {'self': url_for(self.view, **kwargs),
                            'related': url_for(related_view, **related_view_kwargs)},
                  'data': data}

        qs = QSManager(request.args, self.schema)
        if qs.include:
            schema = compute_schema(self.schema, dict(), qs, qs.include)

            serialized_obj = schema.dump(obj)
            result['included'] = serialized_obj.data.get('included', dict())

        return result
Esempio n. 4
0
    def get(self, *args, **kwargs):
        """Retrieve a collection of objects"""
        self.before_get(args, kwargs)

        qs = QSManager(request.args)

        objects_count, objects = self.get_collection(qs, kwargs)

        schema_kwargs = getattr(self, 'get_schema_kwargs', dict())
        schema_kwargs.update({'many': True})

        schema = compute_schema(self.get_schema(objects, kwargs=kwargs),
                                schema_kwargs,
                                qs,
                                qs.include)

        result = schema.dump(objects).data

        self_url = schema.get_top_level_links(result, many=True)['self']
        add_pagination_links(result,
                             objects_count,
                             qs,
                             self_url)

        result.update({'meta': {'count': objects_count}})

        self.after_get(result)

        return result
Esempio n. 5
0
    def delete(self, *args, **kwargs):
        """Delete relationship(s)
        """
        json_data = request.get_json()

        relationship_field, related_type_, related_id_field = self._get_relationship_data()

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

        obj_, updated = self.data_layer.delete_relationship(json_data, relationship_field, related_id_field, **kwargs)

        qs = QSManager(request.args, self.schema)
        schema = compute_schema(self.schema, dict(), qs, qs.include)

        status_code = 200 if updated is True else 204

        return schema.dump(obj_), status_code
Esempio n. 6
0
    def get(self, *args, **kwargs):
        """Retrieve a collection of objects"""
        self.before_get(args, kwargs)

        qs = QSManager(request.args, self.schema)

        objects_count, objects = self.get_collection(qs, kwargs)

        schema_kwargs = getattr(self, 'get_schema_kwargs', dict())
        schema_kwargs.update({'many': True})

        self.before_marshmallow(args, kwargs)

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

        result = schema.dump(objects).data

        view_kwargs = request.view_args if getattr(self, 'view_kwargs',
                                                   None) is True else dict()
        add_pagination_links(result, objects_count, qs,
                             url_for(self.view, _external=True, **view_kwargs))

        result.update({'meta': {'count': objects_count}})

        final_result = self.after_get(result)

        return final_result
Esempio n. 7
0
    def post(self, *args, **kwargs):
        """Create an object"""

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self, 'post_schema_kwargs', dict()),
                                qs, qs.include + self.default_include)

        data = self._validate_schema(args, kwargs, schema)
        if isinstance(data, tuple):
            return data

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

        obj = self.create_object(data, kwargs)

        result = schema.dump(obj)

        if result['data'].get('links', {}).get('self'):
            final_result = (result, 201, {
                'Location': result['data']['links']['self']
            })
        else:
            final_result = (result, 201)

        result = self.after_post(final_result)

        return result
Esempio n. 8
0
    def get(self, *args, **kwargs):
        """Get a relationship details"""
        self.before_get(args, kwargs)

        relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data(
        )

        obj, data = self._data_layer.get_relationship(model_relationship_field,
                                                      related_type_,
                                                      related_id_field, kwargs)

        result = {
            'links': {
                'self':
                request.path,
                'related':
                self.schema._declared_fields[relationship_field].
                get_related_url(obj)
            },
            'data': data
        }

        qs = QSManager(request.args, self.schema)
        if qs.include:
            schema = compute_schema(self.schema, dict(), qs, qs.include)

            serialized_obj = schema.dump(obj)
            result['included'] = serialized_obj.data.get('included', dict())

        final_result = self.after_get(result)

        return final_result
Esempio n. 9
0
    def get(self, *args, **kwargs):
        """Retrieve a collection of items
        """
        qs = QSManager(request.args)

        try:
            item_count, items = self.data_layer.get_items(qs, **kwargs)
        except EntityNotFound as e:
            return ErrorFormatter.format_error([e.message]), e.status_code

        schema_kwargs = self.schema.get('get_kwargs', {})
        if qs.fields.get(self.resource_type):
            if schema_kwargs.get('only'):
                schema_kwargs['only'] = tuple(
                    set(schema_kwargs['only'])
                    & set(self.schema['cls']._declared_fields.keys())
                    & set(qs.fields[self.resource_type]))
            else:
                schema_kwargs['only'] = tuple(
                    set(self.schema['cls']._declared_fields.keys())
                    & set(qs.fields[self.resource_type]))
        if schema_kwargs.get('only') and 'id' not in schema_kwargs['only']:
            schema_kwargs['only'] += ('id', )
        schema_kwargs.pop('many', None)
        schema = self.schema['cls'](many=True, **schema_kwargs)

        result = schema.dump(items)

        endpoint_kwargs = request.view_args if self.endpoint.get(
            'include_view_kwargs') is True else {}
        add_pagination_links(
            result.data, item_count, qs,
            url_for(self.endpoint.get('name'), **endpoint_kwargs))

        return result.data
Esempio n. 10
0
    def patch(self, *args, **kwargs):

        qs = QSManager(request.args, self.schema)

        schema_kwargs = getattr(self, 'patch_schema_kwargs', dict())
        schema_kwargs.update({'partial': True})

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

        json_data = request.get_json() or {}

        self.before_patch(args, kwargs, data=json_data)
        objs = []
        for data in json_data['data']:
            obj = schema.load({'data': data}).data
            obj['id'] = data['id']
            objs += [obj]

        result_objs = self.update_list(objs, qs, kwargs)

        schema_kwargs.update({'many': True})
        many_schema = compute_schema(self.schema, schema_kwargs, qs,
                                     qs.include)
        result = many_schema.dump(result_objs).data

        self.after_patch(result)

        return (result, 200)
Esempio n. 11
0
    def post(self, *args, **kwargs):
        """Create an object"""
        json_data = request.get_json() or {}

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self, 'post_schema_kwargs', dict()),
                                qs, qs.include)

        try:
            if isinstance(json_data['data'], list):
                list_data = []
                errors = None
                for data in json_data['data']:
                    data, obj_errors = schema.load({'data': data})
                    list_data += [data]
            else:
                data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

        self.before_post(args, kwargs, data=data)
        if isinstance(json_data['data'], list):
            objs = self.create_list(list_data, kwargs)
            result = schema.dump(objs).data
            final_result = (result, 201)
        else:
            obj = self.create_object(data, kwargs)
            result = schema.dump(obj).data

            if result['data'].get('links', {}).get('self'):
                final_result = (result, 201, {
                    'Location': result['data']['links']['self']
                })
            else:
                final_result = (result, 201)

        result = self.after_post(final_result)

        return result
Esempio n. 12
0
    def patch(self, *args, **kwargs):
        """Update a relationship"""
        json_data = request.get_json() or {}

        relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data(
        )

        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'})

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

        obj_, updated = self._data_layer.update_relationship(
            json_data, model_relationship_field, related_id_field, kwargs)

        qs = QSManager(request.args, self.schema)
        includes = qs.include
        if relationship_field not in qs.include:
            includes.append(relationship_field)
        schema = compute_schema(self.schema, dict(), qs, includes)

        if updated is False:
            return '', 204

        result = schema.dump(obj_).data
        if result.get('links', {}).get('self') is not None:
            result['links']['self'] = request.path

        self.after_patch(result)

        return result, 200
Esempio n. 13
0
    def patch(self, *args, **kwargs):
        """Update an object"""
        json_data = request.get_json() or {}

        qs = QSManager(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)

        try:
            data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

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

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

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

        result = schema.dump(obj).data

        self.after_patch(result)

        return result
Esempio n. 14
0
    def delete(self, *args, **kwargs):
        """Delete relationship(s)
        """
        self.before_delete(args, kwargs)

        json_data = request.get_json()

        relationship_field, model_relationship_field, related_type_, related_id_field = self._get_relationship_data(
        )

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

        obj_, updated = self._data_layer.delete_relationship(
            json_data, model_relationship_field, related_id_field, kwargs)

        qs = QSManager(request.args, self.schema)
        includes = qs.include
        if relationship_field not in qs.include:
            includes.append(relationship_field)
        schema = compute_schema(self.schema, dict(), qs, includes)

        status_code = 200 if updated is True else 204
        result = schema.dump(obj_).data
        if result.get('links', {}).get('self') is not None:
            result['links']['self'] = request.path
        self.after_delete(result)
        return result, status_code
Esempio n. 15
0
    def get(self, *args, **kwargs):
        """Get object details
        """
        obj = self.data_layer.get_object(**kwargs)

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self.opts, 'schema_get_kwargs', dict()),
                                qs,
                                qs.include)

        result = schema.dump(obj)

        return result.data
Esempio n. 16
0
    def patch(self, *args, **kwargs):
        """Update an object
        """
        json_data = request.get_json()

        qs = QSManager(request.args, self.schema)
        schema_kwargs = getattr(self.opts, 'schema_patch_kwargs', dict())
        schema_kwargs.update({'partial': True})

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

        try:
            data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

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

        obj = self.data_layer.get_object(**kwargs)
        updated = self.data_layer.update_object(obj, data, **kwargs)

        result = schema.dump(obj)

        status_code = 200 if updated is True else 204
        return result.data, status_code
Esempio n. 17
0
    def post(self, *args, **kwargs):
        """Create an object"""
        json_data = request.get_json() or {}

        qs = QSManager(request.args)

        schema = compute_schema(self.get_schema(json_data, is_load=True, kwargs=kwargs),
                                getattr(self, 'post_schema_kwargs', dict()),
                                qs,
                                qs.include)

        try:
            data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

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

        obj = self.create_object(data, kwargs)

        result = schema.dump(obj).data

        self.after_post(result)

        if result['data'].get('links', {}).get('self'):
            final_result = (result, 201, {'Location': result['data']['links']['self']})
        else:
            final_result = (result, 201)

        return final_result
Esempio n. 18
0
    def get(self, *args, **kwargs):
        """Get object details
        """
        self.before_get(args, kwargs)

        obj = self._data_layer.get_object(kwargs)

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self, 'get_schema_kwargs', dict()), qs,
                                qs.include)

        result = schema.dump(obj).data

        self.after_get(result)
        return result
Esempio n. 19
0
    def get(self, *args, **kwargs):
        """Get object details"""
        self.before_get(args, kwargs)

        qs = QSManager(request.args, self.schema)

        obj = self.get_object(kwargs, qs)

        self.before_marshmallow(args, kwargs)

        schema = compute_schema(self.schema,
                                getattr(self, 'get_schema_kwargs', dict()), qs,
                                qs.include)

        result = schema.dump(obj) if obj else None

        final_result = self.after_get(result)

        return final_result
Esempio n. 20
0
def get_distinct_sort_fields(schema, model, sort=True):
    """Due to the poor code of flask-rest-jsonapi, distinct query needed
       in sessions API to remove duplicate sessions can't be sorted on
       returning subquery, thus we need to add all sort fields in distinct
       group and repeat it in sort group as well"""
    fields = []
    qs = QSManager(request.args, schema)
    for sort_opt in qs.sorting:
        field = sort_opt['field']
        if not hasattr(model, field):
            continue
        field = getattr(model, field)
        if sort:
            field = getattr(field, sort_opt['order'])()
        fields.append(field)
    field = Session.id
    if sort:
        field = field.desc()
    fields.append(field)
    return fields
Esempio n. 21
0
    def patch(self, *args, **kwargs):
        """Update an object"""
        qs = QSManager(request.args, self.schema)
        schema_kwargs = getattr(self, 'patch_schema_kwargs', dict())

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

        data = self._validate_schema(args, kwargs, schema)
        if isinstance(data, tuple):
            return data

        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
Esempio n. 22
0
    def post(self, *args, **kwargs):
        """Create an object
        """
        self.before_post(args, kwargs)

        json_data = request.get_json()

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self, 'post_schema_kwargs', dict()),
                                qs, qs.include)

        try:
            data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

        obj = self._data_layer.create_object(data, kwargs)

        result = schema.dump(obj).data
        self.after_post(result)
        return result, 201, {'Location': result['data']['links']['self']}
Esempio n. 23
0
    def post(self, *args, **kwargs):
        """Create an object
        """
        json_data = request.get_json()

        qs = QSManager(request.args, self.schema)

        schema = compute_schema(self.schema,
                                getattr(self.opts, 'schema_post_kwargs', dict()),
                                qs,
                                qs.include)

        try:
            data, errors = 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

        if errors:
            for error in errors['errors']:
                error['status'] = "422"
                error['title'] = "Validation error"
            return errors, 422

        obj = self.data_layer.create_object(data, **kwargs)

        return schema.dump(obj).data, 201
Esempio n. 24
0
    def get(self, *args, **kwargs):
        """Retrieve a collection of objects
        """
        qs = QSManager(request.args, self.schema)

        object_count, objects = self.data_layer.get_collection(qs, **kwargs)

        schema_kwargs = getattr(self.opts, 'schema_get_kwargs', dict())
        schema_kwargs.update({'many': True})

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

        result = schema.dump(objects)

        view_kwargs = request.view_args if getattr(self.opts, 'view_kwargs', None) is True else dict()
        add_pagination_links(result.data,
                             object_count,
                             qs,
                             url_for(self.view, **view_kwargs))

        return result.data
Esempio n. 25
0
def test_qs_manager():
    with pytest.raises(ValueError):
        QSManager([], None)