Пример #1
0
def create_args():
    """Defines and validates params for index"""
    return {
        "team_id":
        fields.UUID(missing=None),
        "file_ids":
        fields.List(fields.UUID(), load_from="image_ids", location="json"),
    }
Пример #2
0
class DumpHoleSchema(Schema):
    uuid = fields.UUID()
    course_uuid = fields.UUID()
    ctime = fields.Integer()
    mtime = fields.Integer()
    name = fields.String()
    number = fields.Integer()
    par = fields.Integer()
    distance = fields.Integer()
Пример #3
0
class CourseApprovedSchema(Schema):
    uuid = fields.UUID(attribute='course.uuid')
    created_by = fields.UUID(attribute='course.created_by')
    message = fields.String()

    @pre_dump
    def prepare(self, data, **kwargs):
        course = data['course']
        data['message'] = f"{course.name} has been approved"
        return data
Пример #4
0
class TemperatureReadingsSchema(ma.mallow.Schema):
    # class Meta:
    # fields = ("log_id", "device_id", "temperature", "time", "url")
    log_id = fields.UUID()
    device_id = fields.UUID()
    temperature = fields.Decimal(attribute='value')
    timestamp = fields.Method('get_time')
    device_name = fields.String()
    location = fields.String()
    units = fields.String()
    url = ma.mallow.URLFor('TemperatureReadingsView:get',
                           log_id='<log_id>',
                           _external=True)

    def get_time(self, obj):
        return obj['time']
Пример #5
0
def update_args():
    """Defines and validates params for update"""
    return {
        "id": fields.UUID(required=True, location="view_args"),
        "user_tags": fields.List(fields.String(), missing=[],
                                 load_from="tags"),
    }
Пример #6
0
class TestListSchema(ma.Schema):
    _links = ma.Hyperlinks({
        'collection': ma.AbsoluteURLFor('testlistresource'),
    })

    id = fields.UUID()
    name = fields.Str()
def suggested_tags_args():
    """Defines and validates suggested tags params"""
    return {
        "team_id": fields.UUID(required=True),
        "tags": fields.List(fields.String(), missing=[]),
        "min_support": fields.Number(missing=0.25, validate=lambda val: val <= 1),
        "limit": fields.Integer(missing=3),
    }
Пример #8
0
def create_args():
    """Defines and validates params for create"""
    return {
        "drive_id": fields.String(required=True),
        "team_id": fields.UUID(required=True, location="view_args"),
        "url": fields.String(),
        "name": fields.String(),
    }
Пример #9
0
class PatientResource(Resource):
    @api.doc("get_patient")
    @use_args(
        {
            "patient_uuid": fields.UUID(location="view_args"),
            "only_dermographic": fields.Boolean(
                location="querystring", missing=False
            ),
        }
    )
    def get(self, args, **kwargs):
        """Get patient with the UUID"""
        if args["only_dermographic"]:
            patient_schema = PatientSchema(
                many=False, exclude=PatientModel.relationship_keys
            )

        else:
            patient_schema = PatientSchema(many=False)

        patient = PatientModel.query.filter_by(id=args["patient_uuid"]).first()

        return patient_schema.dump(patient), 200

    @api.doc("modify_existing_patient")
    def patch(self, patient_uuid):
        """Modify patient with the UUID"""
        patient_schema = PatientSchema(many=False)

        patient_payload = parser.parse(PatientSchema, request)
        patient_payload = patient_schema.dump(patient_payload)

        patient = PatientModel.query.filter_by(id=patient_uuid).first()

        if patient:
            patient.update(**patient_payload)

            db.session.add(patient)
            db.session.commit()

            return patient_schema.dump(patient), 200

        else:
            abort(404, "Patient not found.")

    @api.doc("delete_existing_patient")
    def delete(self, patient_uuid):
        """Delete patient with the UUID"""
        patient = PatientModel.query.filter_by(id=patient_uuid).first()

        if patient:
            patient.deleted = True

            db.session.add(patient)
            db.session.commit()

        return None, 204
Пример #10
0
def update_args():
    """Defines and validates params for update"""
    return {
        "id": fields.UUID(required=True, load_from="id", location="view_args"),
        "username": fields.String(validate=validate.Length(min=1)),
        "email": fields.Email(),
        "password": fields.String(),
        "old_password": fields.String(),
    }
Пример #11
0
class CodeListSchema(ma.Schema):
    _links = ma.Hyperlinks({
        'self':
        ma.AbsoluteURLFor('coderesource', cid='<id>'),
        'collection':
        ma.AbsoluteURLFor('codelistresource'),
    })

    id = fields.UUID()
    name = fields.Str()
Пример #12
0
class DumpSportSchema(Schema):
    uuid = fields.UUID()
    ctime = fields.Integer()
    mtime = fields.Integer()
    name = fields.String()

    def get_attribute(self, obj, attr, default):
        return getattr(obj, attr, default)

    @post_dump
    def make_obj(self, data, **kwargs):
        return data
Пример #13
0
def update_many_args():
    """Defines and validates params for update many"""
    return {
        "artifacts":
        fields.List(
            fields.Nested({
                "id":
                fields.UUID(required=True),
                "user_tags":
                fields.List(fields.String(), required=True, load_from="tags"),
            }))
    }
Пример #14
0
class CodeCommandListSchema(ma.Schema):
    _links = ma.Hyperlinks({
        'self':
        ma.AbsoluteURLFor('codecommandresource',
                          cid='<code_id>',
                          mid='<machine_id>'),
        'collection':
        ma.AbsoluteURLFor('codecommandlistresource', cid='<code_id>'),
    })

    machine_id = fields.UUID()
    machine_name = fields.Str(attribute='machine.name')
    machine_shortname = fields.Str(attribute='machine.shortname')
Пример #15
0
def search_args():
    """Defines and validates params for index"""
    return {
        "search": fields.String(missing=None),
        "team_id": fields.UUID(missing=None),
        "types": fields.String(load_from="type", missing="image"),
        "pipeline": fields.Integer(),
        "start_date": fields.DateTime(),
        "end_date": fields.DateTime(),
        "offset": fields.Integer(missing=0),
        "limit": fields.Integer(missing=12),
        "notify_clients": fields.Boolean(missing=False),
    }
Пример #16
0
def create_args():
    """Defines and validates params for create"""
    return {
        "type":
        fields.String(missing="image"),
        "file":
        fields.Function(deserialize=validate_image,
                        required=True,
                        location="files",
                        load_from="image"),
        "team_id":
        fields.UUID(missing=None),
        "user_tags":
        fields.List(fields.String(), load_from="tags"),
    }
Пример #17
0
class CalculationSchema(CalculationListSchema):
    id = fields.UUID()
    collection = fields.Str(attribute='collection.name')
    code = fields.Str(attribute='code.name')
    structure = fields.Nested('StructureSchema',
                              only=(
                                  'id',
                                  'name',
                                  '_links',
                              ))
    test = fields.Str(attribute='test.name')
    tasks = fields.Nested('Task2ListSchema', many=True)
    testresults = fields.Nested('TestResultSchema',
                                many=True,
                                exclude=('calculations', ))
    metadata = fields.Dict(attribute='mdata')

    _links = ma.Hyperlinks({
        'self':
        ma.AbsoluteURLFor('calculationresource', cid='<id>'),
        'preview':
        ma.AbsoluteURLFor('calculationpreviewresource', cid='<id>'),
        'collection':
        ma.AbsoluteURLFor('calculationlistresource'),
        'tasks':
        ma.AbsoluteURLFor('calculationtask2listresource', cid='<id>'),
    })

    basis_sets = fields.Nested(CalculationBasisSetAssociationSchema,
                               attribute='basis_set_associations',
                               many=True)

    pseudos = fields.Nested(PseudopotentialSchema,
                            many=True,
                            exclude=(
                                'pseudo',
                                'converted_from',
                            ))

    class Meta:
        model = Calculation
        exclude = (
            'basis_set_associations',
            'tasks_query',
            'testresults_query',
            'mdata',
        )
Пример #18
0
class CalculationListSchema(ma.Schema):
    id = fields.UUID()
    collection = fields.Str(attribute='collection.name')
    code = fields.Str(attribute='code.name')
    structure = fields.Str(attribute='structure.name')
    test = fields.Str(attribute='test.name')
    results_available = fields.Bool()
    current_task = fields.Nested('Task2ListSchema')
    _links = ma.Hyperlinks({
        'self':
        ma.AbsoluteURLFor('calculationresource', cid='<id>'),
        'preview':
        ma.AbsoluteURLFor('calculationpreviewresource', cid='<id>'),
        'collection':
        ma.AbsoluteURLFor('calculationlistresource'),
        'tasks':
        ma.AbsoluteURLFor('calculationtask2listresource', cid='<id>'),
    })
Пример #19
0
class Task2ListSchema(ma.Schema):
    id = fields.UUID()
    status = fields.Str(attribute='status.name')
    ctime = fields.DateTime()
    mtime = fields.DateTime()
    machine = fields.Str(attribute='machine.name')
    priority = fields.Int()

    _links = ma.Hyperlinks({
        'self':
        ma.AbsoluteURLFor('task2resource', tid='<id>'),
        'collection':
        ma.AbsoluteURLFor('task2listresource'),
        'uploads':
        ma.AbsoluteURLFor('task2uploadresource', tid='<id>'),
        'calculation':
        ma.AbsoluteURLFor('calculationresource', cid='<calculation_id>'),
    })
Пример #20
0
class DumpCourseSchema(Schema):
    uuid = fields.UUID()
    ctime = fields.Integer()
    mtime = fields.Integer()
    name = fields.String()
    status = EnumField(StatusEnum)
    line_1 = fields.String()
    line_2 = fields.String()
    city = fields.String()
    province = fields.String()
    country = fields.String()
    holes = fields.List(fields.Nested('DumpHoleSchema'))

    def get_attribute(self, obj, attr, default):
        if attr == 'country':
            return obj.country.code if getattr(obj, 'country',
                                               None) else default
        return getattr(obj, attr, default)

    @post_dump
    def make_obj(self, data, **kwargs):
        return data
Пример #21
0
class ObjectResource(ContentNegotiatedMethodView):
    """Object item resource."""

    delete_args = {
        'version_id': fields.UUID(
            location='query',
            load_from='versionId',
            missing=None,
        ),
        'upload_id': fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        ),
        'uploads': fields.Raw(
            location='query',
            validate=invalid_subresource_validator,
        ),
    }

    get_args = dict(
        delete_args,
        download=fields.Raw(
            location='query',
            missing=None,
        )
    )

    post_args = {
        'uploads': fields.Raw(
            location='query',
        ),
        'upload_id': fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        )
    }

    put_args = {
        'upload_id': fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        ),
    }

    multipart_init_args = {
        'size': fields.Int(
            locations=('query', 'json'),
            missing=None,
        ),
        'part_size': fields.Int(
            locations=('query', 'json'),
            missing=None,
            load_from='partSize',
        ),
    }

    def __init__(self, *args, **kwargs):
        """Instantiate content negotiated view."""
        super(ObjectResource, self).__init__(*args, **kwargs)

    #
    # ObjectVersion helpers
    #
    @staticmethod
    def check_object_permission(obj):
        """Retrieve object and abort if it doesn't exists."""
        check_permission(current_permission_factory(
            obj,
            'object-read'
        ))
        if not obj.is_head:
            check_permission(
                current_permission_factory(obj, 'object-read-version'),
                hidden=False
            )

    @classmethod
    def get_object(cls, bucket, key, version_id):
        """Retrieve object and abort if it doesn't exists.

        If the file is not found, the connection is aborted and the 404
        error is returned.

        :param bucket: The bucket (instance or id) to get the object from.
        :param key: The file key.
        :param version_id: The version ID.
        :returns: A :class:`invenio_files_rest.models.ObjectVersion` instance.
        """
        obj = ObjectVersion.get(bucket, key, version_id=version_id)
        if not obj:
            abort(404, 'Object does not exists.')

        cls.check_object_permission(obj)

        return obj

    def create_object(self, bucket, key):
        """Create a new object.

        :param bucket: The bucket (instance or id) to get the object from.
        :param key: The file key.
        :returns: A Flask response.
        """
        # Initial validation of size based on Content-Length.
        # User can tamper with Content-Length, so this is just an initial up
        # front check. The storage subsystem must validate the size limit as
        # well.
        stream, content_length, content_md5, tags = \
            current_files_rest.upload_factory()

        size_limit = bucket.size_limit
        if content_length and size_limit and content_length > size_limit:
            desc = 'File size limit exceeded.' \
                if isinstance(size_limit, int) else size_limit.reason
            raise FileSizeError(description=desc)

        with db.session.begin_nested():
            obj = ObjectVersion.create(bucket, key)
            obj.set_contents(
                stream, size=content_length, size_limit=size_limit)
            # Check add tags
            if tags:
                for key, value in tags.items():
                    ObjectVersionTag.create(obj, key, value)

        db.session.commit()
        return self.make_response(
            data=obj,
            context={
                'class': ObjectVersion,
                'bucket': bucket,
            },
            etag=obj.file.checksum
        )

    @need_permissions(
        lambda self, bucket, obj, *args: obj,
        'object-delete',
        hidden=False,  # Because get_object permission check has already run
    )
    def delete_object(self, bucket, obj, version_id):
        """Delete an existing object.

        :param bucket: The bucket (instance or id) to get the object from.
        :param obj: A :class:`invenio_files_rest.models.ObjectVersion`
            instance.
        :param version_id: The version ID.
        :returns: A Flask response.
        """
        if version_id is None:
            # Create a delete marker.
            with db.session.begin_nested():
                ObjectVersion.delete(bucket, obj.key)
        else:
            # Permanently delete specific object version.
            check_permission(
                current_permission_factory(bucket, 'object-delete-version'),
                hidden=False,
            )
            obj.remove()
            # Set newest object as head
            if obj.is_head:
                obj_to_restore = \
                    ObjectVersion.get_versions(obj.bucket,
                                               obj.key,
                                               desc=True).first()
                if obj_to_restore:
                    obj_to_restore.is_head = True

            if obj.file_id:
                remove_file_data.delay(str(obj.file_id))

        db.session.commit()
        return self.make_response('', 204)

    @staticmethod
    def send_object(bucket, obj, expected_chksum=None,
                    logger_data=None, restricted=True, as_attachment=False):
        """Send an object for a given bucket.

        :param bucket: The bucket (instance or id) to get the object from.
        :param obj: A :class:`invenio_files_rest.models.ObjectVersion`
            instance.
        :params expected_chksum: Expected checksum.
        :param logger_data: The python logger.
        :param kwargs: Keyword arguments passed to ``Object.send_file()``
        :returns: A Flask response.
        """
        if not obj.is_head:
            check_permission(
                current_permission_factory(obj, 'object-read-version'),
                hidden=False
            )

        if expected_chksum and obj.file.checksum != expected_chksum:
            current_app.logger.warning(
                'File checksum mismatch detected.', extra=logger_data)

        file_downloaded.send(current_app._get_current_object(), obj=obj)
        return obj.send_file(restricted=restricted,
                             as_attachment=as_attachment)

    #
    # MultipartObject helpers
    #
    @pass_multipart(with_completed=True)
    @need_permissions(
        lambda self, multipart: multipart,
        'multipart-read'
    )
    def multipart_listparts(self, multipart):
        """Get parts of a multipart upload.

        :param multipart: A :class:`invenio_files_rest.models.MultipartObject`
            instance.
        :returns: A Flask response.
        """
        return self.make_response(
            data=Part.query_by_multipart(
                multipart).order_by(Part.part_number).limit(1000).all(),
            context={
                'class': Part,
                'multipart': multipart,
                'many': True,
            }
        )

    @use_kwargs(multipart_init_args)
    def multipart_init(self, bucket, key, size=None, part_size=None):
        """Initialize a multipart upload.

        :param bucket: The bucket (instance or id) to get the object from.
        :param key: The file key.
        :param size: The total size.
        :param part_size: The part size.
        :raises invenio_files_rest.errors.MissingQueryParameter: If size or
            part_size are not defined.
        :returns: A Flask response.
        """
        if size is None:
            raise MissingQueryParameter('size')
        if part_size is None:
            raise MissingQueryParameter('partSize')
        multipart = MultipartObject.create(bucket, key, size, part_size)
        db.session.commit()
        return self.make_response(
            data=multipart,
            context={
                'class': MultipartObject,
                'bucket': bucket,
            }
        )

    @pass_multipart(with_completed=True)
    def multipart_uploadpart(self, multipart):
        """Upload a part.

        :param multipart: A :class:`invenio_files_rest.models.MultipartObject`
            instance.
        :returns: A Flask response.
        """
        content_length, part_number, stream, content_type, content_md5, tags =\
            current_files_rest.multipart_partfactory()

        if content_length:
            ck = multipart.last_part_size if \
                part_number == multipart.last_part_number \
                else multipart.chunk_size

            if ck != content_length:
                raise MultipartInvalidChunkSize()

        # Create part
        try:
            p = Part.get_or_create(multipart, part_number)
            p.set_contents(stream)
            db.session.commit()
        except Exception:
            # We remove the Part since incomplete data may have been written to
            # disk (e.g. client closed connection etc.) so it must be
            # reuploaded.
            db.session.rollback()
            Part.delete(multipart, part_number)
            raise
        return self.make_response(
            data=p,
            context={
                'class': Part,
            },
            etag=p.checksum
        )

    @pass_multipart(with_completed=True)
    def multipart_complete(self, multipart):
        """Complete a multipart upload.

        :param multipart: A :class:`invenio_files_rest.models.MultipartObject`
            instance.
        :returns: A Flask response.
        """
        multipart.complete()
        db.session.commit()

        version_id = str(uuid.uuid4())

        return self.make_response(
            data=multipart,
            context={
                'class': MultipartObject,
                'bucket': multipart.bucket,
                'object_version_id': version_id,
            },
            # This will wait for the result, and send whitespace on the
            # connection until the task has finished (or max timeout reached).
            task_result=merge_multipartobject.delay(
                str(multipart.upload_id),
                version_id=version_id,
            ),
        )

    @pass_multipart()
    @need_permissions(
        lambda self, multipart: multipart,
        'multipart-delete',
    )
    def multipart_delete(self, multipart):
        """Abort a multipart upload.

        :param multipart: A :class:`invenio_files_rest.models.MultipartObject`
            instance.
        :returns: A Flask response.
        """
        multipart.delete()
        db.session.commit()
        if multipart.file_id:
            remove_file_data.delay(str(multipart.file_id))
        return self.make_response('', 204)

    #
    # HTTP methods implementations
    #
    @use_kwargs(get_args)
    @pass_bucket
    def get(self, bucket=None, key=None, version_id=None, upload_id=None,
            uploads=None, download=None):
        """Get object or list parts of a multpart upload.

        :param bucket: The bucket (instance or id) to get the object from.
            (Default: ``None``)
        :param key: The file key. (Default: ``None``)
        :param version_id: The version ID. (Default: ``None``)
        :param upload_id: The upload ID. (Default: ``None``)
        :param download: The download flag. (Default: ``None``)
        :returns: A Flask response.
        """
        if upload_id:
            return self.multipart_listparts(bucket, key, upload_id)
        else:
            obj = self.get_object(bucket, key, version_id)
            # If 'download' is missing from query string it will have
            # the value None.
            return self.send_object(bucket, obj,
                                    as_attachment=download is not None)

    @use_kwargs(post_args)
    @pass_bucket
    @need_bucket_permission('bucket-update')
    @ensure_input_stream_is_not_exhausted
    def post(self, bucket=None, key=None, uploads=missing, upload_id=None):
        """Upload a new object or start/complete a multipart upload.

        :param bucket: The bucket (instance or id) to get the object from.
            (Default: ``None``)
        :param key: The file key. (Default: ``None``)
        :param upload_id: The upload ID. (Default: ``None``)
        :returns: A Flask response.
        """
        if uploads is not missing:
            return self.multipart_init(bucket, key)
        elif upload_id is not None:
            return self.multipart_complete(bucket, key, upload_id)
        abort(403)

    @use_kwargs(put_args)
    @pass_bucket
    @need_bucket_permission('bucket-update')
    @ensure_input_stream_is_not_exhausted
    def put(self, bucket=None, key=None, upload_id=None):
        """Update a new object or upload a part of a multipart upload.

        :param bucket: The bucket (instance or id) to get the object from.
            (Default: ``None``)
        :param key: The file key. (Default: ``None``)
        :param upload_id: The upload ID. (Default: ``None``)
        :returns: A Flask response.
        """
        if upload_id is not None:
            return self.multipart_uploadpart(bucket, key, upload_id)
        else:
            return self.create_object(bucket, key)

    @use_kwargs(delete_args)
    @pass_bucket
    def delete(self, bucket=None, key=None, version_id=None, upload_id=None,
               uploads=None):
        """Delete an object or abort a multipart upload.

        :param bucket: The bucket (instance or id) to get the object from.
            (Default: ``None``)
        :param key: The file key. (Default: ``None``)
        :param version_id: The version ID. (Default: ``None``)
        :param upload_id: The upload ID. (Default: ``None``)
        :returns: A Flask response.
        """
        if upload_id is not None:
            return self.multipart_delete(bucket, key, upload_id)
        else:
            obj = self.get_object(bucket, key, version_id)
            return self.delete_object(bucket, obj, version_id)
Пример #22
0
class ObjectResource(ContentNegotiatedMethodView):
    """"Object item resource."""

    get_args = {
        'version_id':
        fields.UUID(
            location='query',
            load_from='versionId',
            missing=None,
        ),
        'upload_id':
        fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        )
    }

    delete_args = get_args

    post_args = {
        'uploads':
        fields.Raw(
            location='query',
            missing=False,
        ),
        'upload_id':
        fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        )
    }

    put_args = {
        'upload_id':
        fields.UUID(
            location='query',
            load_from='uploadId',
            missing=None,
        ),
    }

    upload_headers = {
        'content_md5':
        fields.Str(
            load_from='Content-MD5',
            location='headers',
            missing=None,
        ),
        'content_length':
        fields.Int(
            load_from='Content-Length',
            location='headers',
            required=True,
            validate=minsize_validator,
        )
    }

    multipart_init_args = {
        'size': fields.Int(
            locations=('query', 'json'),
            required=True,
        ),
        'part_size': fields.Int(
            locations=('query', 'json'),
            required=True,
        ),
    }

    #
    # ObjectVersion helpers
    #
    @staticmethod
    def get_object(bucket, key, version_id):
        """Retrieve object and abort if it doesn't exists."""
        obj = ObjectVersion.get(bucket, key, version_id=version_id)
        if not obj:
            abort(404, 'Object does not exists.')

        check_permission(current_permission_factory(obj, 'object-read'))
        if not obj.is_head:
            check_permission(current_permission_factory(
                obj, 'object-read-version'),
                             hidden=False)
        return obj

    @staticmethod
    @use_kwargs(upload_headers)
    def create_object(bucket,
                      key,
                      uploaded_file=None,
                      content_md5=None,
                      content_length=None):
        """Create a new object."""
        # Initial validation of size based on Content-Length.
        # User can tamper with Content-Length, so this is just an initial up
        # front check. The storage subsystem must validate the size limit as
        # well.
        size_limit = bucket.size_limit
        if size_limit and content_length > size_limit:
            desc = 'File size limit exceeded.' \
                if isinstance(size_limit, int) else size_limit.reason
            raise FileSizeError(description=desc)

        with db.session.begin_nested():
            obj = ObjectVersion.create(bucket, key)
            obj.set_contents(request.stream,
                             size=content_length,
                             size_limit=size_limit)
        db.session.commit()
        return obj

    @need_permissions(
        lambda self, bucket, obj, *args: obj,
        'object-delete',
        hidden=False,  # Because get_object permission check has already run
    )
    def delete_object(self, bucket, obj, version_id):
        """Delete an existing object."""
        if version_id is None:
            # Create a delete marker.
            with db.session.begin_nested():
                ObjectVersion.delete(bucket, obj.key)
            db.session.commit()
        else:
            # Permanently delete specific object version.
            check_permission(
                current_permission_factory(bucket, 'object-delete-version'),
                hidden=False,
            )
            obj.remove()
            db.session.commit()
            if obj.file_id:
                remove_file_data.delay(str(obj.file_id))

        return self.make_response('', 204)

    @staticmethod
    def send_object(bucket,
                    obj,
                    expected_chksum=None,
                    logger_data=None,
                    restricted=True):
        """Send an object for a given bucket."""
        if not obj.is_head:
            check_permission(current_permission_factory(
                obj, 'object-read-version'),
                             hidden=False)

        if expected_chksum and obj.file.checksum != expected_chksum:
            current_app.logger.warning('File checksum mismatch detected.',
                                       extra=logger_data)

        file_downloaded.send(current_app._get_current_object(), obj=obj)
        return obj.send_file(restricted=restricted)

    #
    # MultipartObject helpers
    #
    @pass_multipart(with_completed=True)
    @need_permissions(lambda self, multipart: multipart, 'multipart-read')
    def multipart_listparts(self, multipart):
        """Get parts of a multpart upload."""
        return self.make_response(
            data=Part.query_by_multipart(multipart).order_by(
                Part.part_number).limit(1000).all(),
            context={
                'class': Part,
                'multipart': multipart,
                'many': True,
            })

    @use_kwargs(multipart_init_args)
    def multipart_init(self, bucket, key, size=None, part_size=None):
        """Initiate a multipart upload."""
        multipart = MultipartObject.create(bucket, key, size, part_size)
        db.session.commit()
        return self.make_response(data=multipart,
                                  context={
                                      'class': MultipartObject,
                                      'bucket': bucket,
                                  })

    @use_kwargs(upload_headers)
    @pass_multipart(with_completed=True)
    def multipart_uploadpart(self,
                             multipart,
                             content_md5=None,
                             content_length=None):
        """Upload a part."""
        if content_length != multipart.chunk_size:
            raise MultipartInvalidChunkSize()

        # Extract part number from request.
        data = None
        for schema in current_files_rest.uploadparts_schema_factory:
            try:
                data = parser.parse(schema)
                if data:
                    break
            except UnprocessableEntity:
                pass

        if not data or data.get('part_number') is None:
            raise MultipartInvalidPartNumber()
        part_number = data['part_number']

        # Create part
        try:
            p = Part.get_or_create(multipart, part_number)
            p.set_contents(request.stream)
            db.session.commit()
        except Exception:
            # We remove the Part since incomplete data may have been written to
            # disk (e.g. client closed connection etc.)
            db.session.rollback()
            Part.delete(multipart, part_number)
            raise
        return self.make_response(data=p,
                                  context={
                                      'class': Part,
                                  },
                                  etag=p.checksum)

    @pass_multipart(with_completed=True)
    def multipart_complete(self, multipart):
        """Complete a multipart upload."""
        multipart.complete()
        db.session.commit()
        merge_multipartobject.delay(str(multipart.upload_id))
        return self.make_response(data=multipart,
                                  context={
                                      'class': MultipartObject,
                                      'bucket': multipart.bucket,
                                  })

    @pass_multipart()
    @need_permissions(
        lambda self, multipart: multipart,
        'multipart-delete',
    )
    def multipart_delete(self, multipart):
        """Abort a multipart upload."""
        multipart.delete()
        db.session.commit()
        if multipart.file_id:
            remove_file_data.delay(str(multipart.file_id))
        return self.make_response('', 204)

    #
    # HTTP methods implementations
    #
    @use_kwargs(get_args)
    @pass_bucket
    def get(self, bucket=None, key=None, version_id=None, upload_id=None):
        """Get object or list parts of a multpart upload."""
        if upload_id:
            return self.multipart_listparts(bucket, key, upload_id)
        else:
            obj = self.get_object(bucket, key, version_id)
            return self.send_object(bucket, obj)

    @use_kwargs(post_args)
    @pass_bucket
    @need_bucket_permission('bucket-update')
    def post(self, bucket=None, key=None, uploads=None, upload_id=None):
        """Upload a new object or start/complete a multipart upload."""
        if uploads is not False:
            return self.multipart_init(bucket, key)
        elif upload_id is not None:
            return self.multipart_complete(bucket, key, upload_id)
        abort(403)

    @use_kwargs(put_args)
    @pass_bucket
    @need_bucket_permission('bucket-update')
    def put(self, bucket=None, key=None, upload_id=None):
        """Update a new object or upload a part of a multipart upload."""
        if upload_id is not None:
            return self.multipart_uploadpart(bucket, key, upload_id)
        else:
            return self.create_object(bucket, key)

    @use_kwargs(delete_args)
    @pass_bucket
    def delete(self, bucket=None, key=None, version_id=None, upload_id=None):
        """Delete an object or abort a multipart upload."""
        if upload_id is not None:
            return self.multipart_delete(bucket, key, upload_id)
        else:
            obj = self.get_object(bucket, key, version_id)
            return self.delete_object(bucket, obj, version_id)
def update_args():
    """Defines and validates params for update"""
    return {
        "id": fields.UUID(required=True, location="view_args"),
        "name": fields.String(required=True, validate=validate.Length(min=1)),
    }
def get_args():
    """Defines and validates params for show"""
    return {"id": fields.UUID(required=True, location="view_args")}
def create_args():
    """Defines and validates params for create"""
    return {
        "id": fields.UUID(required=True, location="view_args"),
        "id_token": fields.String(required=True)
    }
def revoke_access_args():
    """Defines and validates params for revoke_access"""
    return {"id": fields.UUID(required=True, location="view_args")}
def update_args():
    """Defines and validates params for update"""
    return {
        "id": fields.UUID(required=True, location="view_args"),
        "auth_code": fields.String(required=True)
    }
Пример #28
0
class DepositFileResource(ContentNegotiatedMethodView):
    """Deposit files resource."""

    view_name = '{0}_file'

    get_args = dict(version_id=fields.UUID(
        location='headers',
        load_from='version_id',
    ), )
    """GET query arguments."""
    def __init__(self, serializers, pid_type, ctx, *args, **kwargs):
        """Constructor."""
        super(DepositFileResource, self).__init__(serializers, *args, **kwargs)
        for key, value in ctx.items():
            setattr(self, key, value)

    @use_kwargs(get_args)
    @pass_record
    @need_record_permission('read_permission_factory')
    def get(self, pid, record, key, version_id=None, **kwargs):
        """Get file.

        Permission required: `read_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        :param version_id: File version. Optional. If no version is provided,
            the last version is retrieved.
        :returns: the file content.
        """
        try:
            obj = record.files[str(key)].get_version(version_id=version_id)
            return self.make_response(obj=obj or abort(404),
                                      pid=pid,
                                      record=record)
        except KeyError:
            abort(404)

    @require_api_auth()
    @require_oauth_scopes(write_scope.id)
    @pass_record
    @need_record_permission('update_permission_factory')
    def put(self, pid, record, key):
        """Handle the file rename through the PUT deposit file.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        """
        try:
            data = json.loads(request.data.decode('utf-8'))
            new_key = data['filename']
        except KeyError:
            raise WrongFile()
        new_key_secure = secure_filename(new_key)
        if not new_key_secure or new_key != new_key_secure:
            raise WrongFile()
        try:
            obj = record.files.rename(str(key), new_key_secure)
        except KeyError:
            abort(404)
        record.commit()
        db.session.commit()
        return self.make_response(obj=obj, pid=pid, record=record)

    @require_api_auth()
    @require_oauth_scopes(write_scope.id)
    @pass_record
    @need_record_permission('update_permission_factory')
    def delete(self, pid, record, key):
        """Handle DELETE deposit file.

        Permission required: `update_permission_factory`.

        :param pid: Pid object (from url).
        :param record: Record object resolved from the pid.
        :param key: Unique identifier for the file in the deposit.
        """
        try:
            del record.files[str(key)]
            record.commit()
            db.session.commit()
            return make_response('', 204)
        except KeyError:
            abort(
                404, 'The specified object does not exist or has already '
                'been deleted.')
    if headers:
        return jsonify({"errors": messages}), err.code, headers
    else:
        return jsonify({"errors": messages}), 422


@app.errorhandler(400)
def handle_error2(err):
    """Flask error handler."""
    messages = err.data.get("messages", ["Invalid request."])
    return jsonify({"_0": "Internal data mismatch", "errors": messages}), 400


@app.route('/', methods=['POST'])
@use_args({
    'sender': fields.UUID(required=True),
    'receiver': fields.UUID(required=True),
    'amount': fields.Decimal(required=True, validate=lambda x: x > 0)
})
def api_main(args):
    """Put json to DB to make a transaction.

    Example:
        {
            "sender": "40e6815d-b5c6-4896-987c-f30f3678f608",
            "receiver": "6ecd8c99-4036-403d-bf84-cf8400f67836",
            "amount": 1
        }

    Args:
        args (dict):
Пример #30
0
class DepositFileResource(ContentNegotiatedMethodView):
    """Deposit files resource."""

    view_name = '{0}_file'

    get_args = dict(version_id=fields.UUID(
        location='headers',
        load_from='version_id',
    ), )
    """GET query arguments."""
    def __init__(self, serializers, pid_type, ctx, *args, **kwargs):
        """Constructor."""
        super(DepositFileResource, self).__init__(serializers, *args, **kwargs)
        for key, value in ctx.items():
            setattr(self, key, value)

    @use_kwargs(get_args)
    @pass_record
    @need_record_permission('read_permission_factory')
    def get(self, pid, record, key, version_id, **kwargs):
        """Get deposit/depositions/:id/files/:key."""
        try:
            obj = record.files[str(key)].get_version(version_id=version_id)
            return self.make_response(obj=obj or abort(404))
        except KeyError:
            abort(404)

    @require_api_auth()
    @require_oauth_scopes(write_scope.id)
    @pass_record
    @need_record_permission('update_permission_factory')
    def put(self, pid, record, key):
        """Handle PUT deposit files."""
        try:
            data = json.loads(request.data.decode('utf-8'))
            new_key = data['filename']
        except KeyError:
            raise WrongFile()
        new_key_secure = secure_filename(new_key)
        if not new_key_secure or new_key != new_key_secure:
            raise WrongFile()
        try:
            obj = record.files.rename(str(key), new_key_secure)
        except KeyError:
            abort(404)
        record.commit()
        db.session.commit()
        return self.make_response(obj=obj)

    @require_api_auth()
    @require_oauth_scopes(write_scope.id)
    @pass_record
    @need_record_permission('update_permission_factory')
    def delete(self, pid, record, key):
        """Handle DELETE deposit files."""
        try:
            del record.files[str(key)]
            record.commit()
            db.session.commit()
            return make_response('', 204)
        except KeyError:
            abort(
                404, 'The specified object does not exist or has already '
                'been deleted.')