Ejemplo n.º 1
0
class CommunityRequestsResource(MethodView):
    """Resource to list community membership requests."""

    post_args = {
        'response':
        fields.Raw(location='json',
                   required=True,
                   validate=[validate.OneOf(['accept', 'decline'])]),
        'role':
        fields.Raw(location='json',
                   required=False,
                   validate=[validate.OneOf(['M', 'A', 'C'])])
    }

    @pass_community
    def get(self,
            comid=None,
            community=None,
            outgoing_only=False,
            incoming_only=False,
            page_size=20,
            page=0):
        """List all the community membership requests."""
        admin_ids = \
            [admin.user.id for admin in CommunityMember.get_admins(
                community.id)]
        if int(current_user.get_id()) not in admin_ids:
            abort(404)
        response_object = {}
        if not outgoing_only:
            count, requests = \
                MembershipRequestAPI.get_community_incoming_requests(
                    community.id, page_size=page_size)
            response_object['inc_count'] = count
            response_object['inc_requests'] = []
            for req in requests:
                response_object['inc_requests'].append({
                    'email': req.email,
                    'req_id': req.id
                })
        if not incoming_only:
            count, requests = \
                MembershipRequestAPI.get_community_outgoing_requests(
                    community.id, page_size=page_size)
            response_object['out_count'] = count
            response_object['out_requests'] = []
            for req in requests:
                response_object['out_requests'].append({
                    'email':
                    req.email,
                    'req_id':
                    req.id,
                    'role':
                    str(req.role.title)
                })
        return jsonify(response_object), 200
Ejemplo n.º 2
0
class BucketResource(ContentNegotiatedMethodView):
    """"Bucket item resource."""

    get_args = {
        'versions': fields.Raw(
            location='query',
            missing=False,
        ),
        'uploads': fields.Raw(
            location='query',
            missing=False,
        )
    }

    @need_permissions(lambda self, bucket: bucket, 'bucket-listmultiparts')
    def multipart_listuploads(self, bucket):
        """List objects in a bucket."""
        return self.make_response(
            data=MultipartObject.query_by_bucket(bucket).limit(1000).all(),
            context={
                'class': MultipartObject,
                'bucket': bucket,
                'many': True,
            })

    @need_permissions(
        lambda self, bucket, versions: bucket,
        'bucket-read',
    )
    def listobjects(self, bucket, versions):
        """List objects in a bucket."""
        if versions is not False:
            check_permission(current_permission_factory(
                bucket, 'bucket-read-versions'),
                             hidden=False)
        return self.make_response(data=ObjectVersion.get_by_bucket(
            bucket.id, versions=versions is not False).limit(1000).all(),
                                  context={
                                      'class': ObjectVersion,
                                      'bucket': bucket,
                                      'many': True,
                                  })

    @use_kwargs(get_args)
    @pass_bucket
    def get(self, bucket=None, versions=None, uploads=None):
        """Get list of objects in the bucket."""
        if uploads is not False:
            return self.multipart_listuploads(bucket)
        else:
            return self.listobjects(bucket, versions)

    @pass_bucket
    @need_bucket_permission('bucket-read')
    def head(self, bucket=None, **kwargs):
        """Check the existence of the bucket."""
Ejemplo n.º 3
0
    def post(self):
        """Uploads a file"""

        file_obj = FlaskParser.parse_files(self,
                                           request,
                                           "upfile",
                                           field=fields.Raw())  # pylint: disable=maybe-no-member

        if isinstance(file_obj, type(
                marshmallow.missing)):  # werkzeug.datastructures.FileStorage
            return {"message": "File missing"}, 400  # Bad request

        size = Upload.get_size(file_obj)

        if size > app.config["MAX_UPLOAD"]:
            return {
                "message":
                "You exceded file limit of {}".format(app.config["MAX_UPLOAD"])
            }, 400

        if file_obj.mimetype != Upload.mimetype:
            return {
                "message":
                "File mimetype is {} instead of {}".format(
                    str(file_obj.mimetype), Upload.mimetype)
            }, 415  # 415 Unsupported Media Type

        file_path = os.path.join(app.config['UPLOAD_FOLDER'],
                                 file_obj.filename)
        file_obj.save(file_path)

        return jsonify(
            message="Saved file:{} with size {} bytes".format(file_path, size))
Ejemplo n.º 4
0
class Main(Resource):
    args = {
        "query": fields.Raw(required=True,
                            validate=validate.Length(1, max=None)),
        "count": fields.Int(required=False,
                            validate=validate.Range(1, max=None))
    }

    def __init__(self, indexer: Indexer):
        self.__indexer = indexer

    @use_args(args)
    def get(self, args):
        queryResult = self.__indexer.query(args["query"])

        if "count" in args:
            return queryResult.jsonify(count=args["count"])
        else:
            return queryResult.jsonify()
Ejemplo n.º 5
0
class BucketResource(ContentNegotiatedMethodView):
    """Bucket item resource."""

    get_args = {
        'versions': fields.Raw(
            location='query',
        ),
        'uploads': fields.Raw(
            location='query',
        )
    }

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

    @need_permissions(lambda self, bucket: bucket, 'bucket-listmultiparts')
    def multipart_listuploads(self, bucket):
        """List objects in a bucket.

        :param bucket: A :class:`invenio_files_rest.models.Bucket` instance.
        :returns: The Flask response.
        """
        return self.make_response(
            data=MultipartObject.query_by_bucket(bucket).limit(1000).all(),
            context={
                'class': MultipartObject,
                'bucket': bucket,
                'many': True,
            }
        )

    @need_permissions(
        lambda self, bucket, versions: bucket,
        'bucket-read',
    )
    def listobjects(self, bucket, versions):
        """List objects in a bucket.

        :param bucket: A :class:`invenio_files_rest.models.Bucket` instance.
        :returns: The Flask response.
        """
        if versions is not missing:
            check_permission(
                current_permission_factory(bucket, 'bucket-read-versions'),
                hidden=False
            )
        return self.make_response(
            data=ObjectVersion.get_by_bucket(
                bucket.id, versions=versions is not missing).limit(1000).all(),
            context={
                'class': ObjectVersion,
                'bucket': bucket,
                'many': True,
            }
        )

    @use_kwargs(get_args)
    @pass_bucket
    def get(self, bucket=None, versions=missing, uploads=missing):
        """Get list of objects in the bucket.

        :param bucket: A :class:`invenio_files_rest.models.Bucket` instance.
        :returns: The Flask response.
        """
        if uploads is not missing:
            return self.multipart_listuploads(bucket)
        else:
            return self.listobjects(bucket, versions)

    @pass_bucket
    @need_bucket_permission('bucket-read')
    def head(self, bucket=None, **kwargs):
        """Check the existence of the bucket."""
Ejemplo n.º 6
0
@use_kwargs({
    'part_number': fields.Int(
        load_from='_chunkNumber',
        location='form',
        required=True,
    ),
    'content_length': fields.Int(
        load_from='_currentChunkSize',
        location='form',
        required=True,
        validate=minsize_validator,
    ),
    'uploaded_file': fields.Raw(
        load_from='file',
        location='files',
        required=True,
    ),
})
def ngfileupload_partfactory(part_number=None, content_length=None,
                             uploaded_file=None):
    """Part factory for ng-file-upload.

    :param part_number: The part number. (Default: ``None``)
    :param content_length: The content length. (Default: ``None``)
    :param uploaded_file: The upload request. (Default: ``None``)
    :returns: The content length, part number, stream, HTTP Content-Type
        header.
    """
    return content_length, part_number, uploaded_file.stream, \
        uploaded_file.headers.get('Content-Type'), None, None
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
        data_key='_chunkNumber',
        location='form',
        required=True,
    ),
    'content_length':
    fields.Int(
        load_from='_currentChunkSize',
        data_key='_currentChunkSize',
        location='form',
        required=True,
        validate=minsize_validator,
    ),
    'uploaded_file':
    fields.Raw(
        load_from='file',
        data_key='file',
        location='files',
        required=True,
    ),
})
def ngfileupload_partfactory(part_number=None,
                             content_length=None,
                             uploaded_file=None):
    """Part factory for ng-file-upload.

    :param part_number: The part number. (Default: ``None``)
    :param content_length: The content length. (Default: ``None``)
    :param uploaded_file: The upload request. (Default: ``None``)
    :returns: The content length, part number, stream, HTTP Content-Type
        header.
    """
    return content_length, part_number, uploaded_file.stream, \
Ejemplo n.º 9
0
class SuccessListSchema(ma.Schema):
    results = fields.List(fields.Raw())
    total = fields.Number()
Ejemplo n.º 10
0
class CommunityMembersResource(MethodView):
    """Resource for creating, listing and removing community memberships."""

    post_args = {
        'role':
        fields.Raw(location='json',
                   required=False,
                   validate=[validate.OneOf(['M', 'A', 'C'])]),
        'email':
        fields.Email(location='json', required=False),
        'request_type':
        fields.Raw(location='json',
                   required=True,
                   validate=[validate.OneOf(['invitation', 'request'])])
    }

    put_args = {
        'role':
        fields.Raw(location='json',
                   required=False,
                   validate=[validate.OneOf(['M', 'A', 'C'])]),
        'user_id':
        fields.Raw(location='json', required=False),
        'email':
        fields.Email(location='json', required=False),
    }

    delete_args = {
        'user_id': fields.Raw(location='query', required=False),
    }

    @use_kwargs(post_args)
    @pass_community
    def post(self,
             comid=None,
             community=None,
             email=None,
             role=None,
             request_type=None,
             **kwargs):
        """Join a community or invite a user to it."""
        if request_type == 'invitation':
            admin_ids = \
                [admin.user.id for admin in CommunityMember.get_admins(
                    community.id)]
            if int(current_user.get_id()) not in admin_ids:
                abort(404)
            existing_membership_req = MembershipRequest.query.filter_by(
                comm_id=community.id, email=email).one_or_none()
            if existing_membership_req:
                abort(400, 'This is an already existing relationship.')
            CommunityMembersAPI.invite_member(community, email, role)
        elif request_type == 'request':
            user_id = int(current_user.get_id())
            email = current_user.email
            CommunityMembersAPI.join_community(user_id, email, community)
        db.session.commit()
        return 'Succesfully Invited', 200

    @pass_community
    def get(self, comid=None, community=None):
        """List the community members."""
        admin_ids = \
            [admin.user.id for admin in CommunityMember.get_admins(
                community.id)]
        if int(current_user.get_id()) not in admin_ids:
            abort(404)
        ui_members = []
        for member in CommunityMembersAPI.get_members(community.id).all():
            add_member = {}
            add_member['user_id'] = str(member.user_id)
            add_member['email'] = member.user.email
            add_member['role'] = str(member.role.title)
            ui_members.append(add_member)
        return jsonify(ui_members), 200

    @use_kwargs(delete_args)
    @pass_community
    def delete(self, comid=None, community=None, user_id=None):
        """Remove a member from a community."""
        admin_ids = \
            [admin.user.id for admin in CommunityMember.get_admins(
                community.id)]
        if int(current_user.get_id()) not in admin_ids:
            abort(404)
        CommunityMembersAPI.delete_member(community.id, user_id)
        db.session.commit()
        return 'Succesfully removed', 204
Ejemplo n.º 11
0
class MembershipRequestResource(MethodView):
    """Resource to view and handle membership requests."""

    post_args = {
        'response':
        fields.Raw(location='json',
                   required=True,
                   validate=[validate.OneOf(['accept', 'decline'])]),
        'role':
        fields.Raw(location='json',
                   required=False,
                   validate=[validate.OneOf(['M', 'A', 'C'])])
    }

    put_args = {
        'role':
        fields.Raw(location='json',
                   required=True,
                   validate=[validate.OneOf(['M', 'A', 'C'])])
    }

    def get(self, membership_request_id):
        """Get the information for a membership request."""
        member_request, community = MembershipRequestAPI.get_invitation(
            membership_request_id)
        response_object = {}
        response_object['community_name'] = community.json['title']
        response_object['community_id'] = community.json['id']
        response_object['role'] = str(member_request.role.title)
        return jsonify(response_object), 200

    @use_kwargs(post_args)
    def post(self, membership_request_id, response=None, role=None):
        """Accept or reject a membership request."""
        if not current_user.is_authenticated:
            abort(404)
        user_id = int(current_user.get_id())
        member_request = MembershipRequest.query.get(membership_request_id)
        if not member_request.is_invite:
            # and current_user.email == request.email):
            community_admins = [
                admin.user.id
                for admin in CommunityMember.get_admins(member_request.comm_id)
            ]
            if not (user_id in community_admins
                    and not member_request.is_invite):
                abort(404)
        if response == 'accept':
            MembershipRequestAPI.accept_invitation(request, role, user_id)
            db.session.commit()
            return 'Succesfully accepted.', 200
        else:
            MembershipRequestAPI.decline_or_cancel_invitation(
                member_request.id)
            db.session.commit()
            return 'Succesfully rejected.', 200

    @use_kwargs(put_args)
    def put(self, membership_request_id, role=None):
        """Modify a membership request."""
        if not current_user.is_authenticated:
            abort(404)
        member_request = MembershipRequest.query.get(membership_request_id)
        community_admins = [
            admin.user.id
            for admin in CommunityMember.get_admins(member_request.comm_id)
        ]
        if not (int(current_user.get_id()) in community_admins
                and member_request.is_invite):
            abort(404)
        member_request.role = role
        db.session.commit()
        return 'Succesfully modified invitaion.', 200

    def delete(self, membership_request_id):
        """Cancel(remove) a membership request."""
        if not current_user.is_authenticated:
            abort(404)
        user_id = int(current_user.get_id())
        member_request = MembershipRequest.query.get(membership_request_id)
        if not (current_user.email == member_request.email
                and not member_request.is_invite):
            community_admins = [
                admin.user.id
                for admin in CommunityMember.get_admins(member_request.comm_id)
            ]
            if not (user_id in community_admins and member_request.is_invite):
                abort(404)
        MembershipRequestAPI.decline_or_cancel_invitation(member_request.id)

        db.session.commit()
        return 'Succesfully cancelled invitation.', 204
Ejemplo n.º 12
0
@login_required
@use_kwargs(projekty_edit_args)
def projekty_edit(project_id):
    project = Project.get_by_id(project_id)
    return render_template('frontend/projekty-edit.html', project=project)


save_project_args = {
    'project_id': fields.Int(required=True),
    'title_pl': fields.Str(required=True),
    'title_en': fields.Str(required=True),
    'description_pl': fields.Str(required=True),
    'description_en': fields.Str(required=True),
    'content_pl': fields.Str(required=True),
    'content_en': fields.Str(required=True),
    'data': fields.Raw(location='files', missing=None),
}


@frontend.route('/edit/submit', methods=['POST'])
@login_required
@use_kwargs(save_project_args)
def save_project(project_id, title_pl, title_en, description_pl,
                 description_en, content_pl, content_en, data):
    project = Project.get_by_id(project_id)
    project.title_pl = title_pl
    project.title_en = title_en
    project.description_pl = description_pl
    project.description_en = description_en
    project.content_pl = content_pl
    project.content_en = content_en