Esempio n. 1
0
def GET(request, api_library, app):
    """
    GET /file/:file_id/data

    Download file data

    To retrieve file data, an application submits an HTTP GET request to the file data resource that
    represents the data for the file.
    """
    try:
        _, _, file_id, _, version, _ = split_path(request.path, 4, 6, False)
    except:
        app.logger.error("StackSync API: data_resource GET: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id/data[/version/:version_id]]")

    app.logger.info('StackSync API: data_resource GET: path info: %s ', str(request.path_info))

    user_id = request.environ["stacksync_user_id"]
    metadata = api_library.get_metadata(user_id, file_id, include_chunks=True,
                                        specific_version=version, is_folder=False)
    response = create_response(metadata, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource GET: status code: %s. body: %s", str(response.status_int),
                         str(response.body))
        return response

    metadata = json.loads(metadata)

    data_handler = DataHandler(app)

    workspace_info = api_library.get_workspace_info(user_id, file_id)
    response = create_response(workspace_info, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource GET: status code: %s. body: %s", str(response.status_int),
                         str(response.body))
        return response

    workspace_info = json.loads(workspace_info)
    container_name = workspace_info['swift_container']
    print 'chunks to retrieve', metadata['chunks']
    file_compress_content, status = data_handler.get_chunks(request.environ, metadata['chunks'],
                                                            container_name)

    if is_valid_status(status):
        if len(file_compress_content) > 0:
            joined_file = BuildFile("", file_compress_content)
            joined_file.join()
            headers = {'Content-Type': metadata['mimetype']}
            return HTTPOk(body=joined_file.content, headers=headers)
        elif len(metadata['chunks']) == 0:
            return HTTPOk(body='')
        else:
            app.logger.error("StackSync API: data_resource GET: Unexpected case. File_id: %s.", str(file_id))
            return create_error_response(500, "Could not retrieve file. Please contact an administrator.")
    else:
        app.logger.error("StackSync API: data_resource GET: Cannot retrieve chunks. File_id: %s. Status: %s",
                         str(file_id), str(status))
        return create_error_response(status, "Cannot retrieve chunks from storage backend.")
Esempio n. 2
0
def PUT(request, api_library, app):
    """
    PUT /folder/:folder_id

    Body parameters (JSON encoded):
        - name: (Optional) The user-visible name of the folder.
        - parent: (Optional) ID of the folder where the folder is going to be moved. If parent is set
                    to '0' the folder will be moved to the root folder.

    Update folder metadata

    An application can update various attributes of a folder by issuing an HTTP PUT request to the URL
    that represents the folder resource. In addition, the app needs to provide as input, JSON that
    identifies the new attribute values for the folder. Upon receiving the PUT request, the StackSync
    service examines the input and updates any of the attributes that have been modified.
    """

    try:
        _, _, folder_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error(
            "StackSync API: folder_resource PUT: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder")

    try:
        params = json.loads(unicode(request.body, 'iso-8859-15'))
    except:
        app.logger.error(
            'StackSync API: folder_resource PUT: status: %s path info: %s',
            str(404), request.path_info)
        return create_error_response(400, "Could not decode body parameters.")

    try:
        parent = params['parent']
    except KeyError:
        parent = None
    try:
        name = params['name']
    except KeyError:
        name = None

    app.logger.info('StackSync API: folder_resource PUT: path info: %s ',
                    str(request.path_info))
    user_id = request.environ["stacksync_user_id"]

    message = api_library.put_metadata(user_id, folder_id, name, parent)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: folder_resource DELETE: error deleting folder in StackSync Server: %s.",
            str(response.status_int))
    return response
Esempio n. 3
0
def GET(request, api_library, app):
    """
    GET /file/:file_id/[versions|version/:version_id]

    Get file versions and version metadata

    To retrieve information about a file version, an application submits an HTTP GET request
    to the file version resource.
    """

    try:
        _, _, file_id, _, version = split_path(request.path, 4, 5, False)
    except:
        app.logger.error(
            "StackSync API: file_resource DELETE: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /file/:file_id")

        app.logger.info(
            'StackSync API: versions_resource GET: error: 400, path info: %s ',
            str(request.path_info))
        return create_error_response(400, "Some problem with path.")

    app.logger.info('StackSync API: versions_resource GET: path info: %s ',
                    str(request.path_info))

    user_id = request.environ["stacksync_user_id"]

    if not version:
        # if no version is given, return the list of versions
        message = api_library.get_versions(user_id, file_id)
        response = create_response(message, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error(
                "StackSync API: versions_resource GET: error getting versions of file: %s.",
                str(file_id))
    else:
        # if a version is given, return metadata about that specific version
        message = api_library.get_metadata(user_id,
                                           file_id,
                                           specific_version=version,
                                           is_folder=False)
        response = create_response(message, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error(
                "StackSync API: versions_resource GET: error getting version of file %s and version %s.",
                str(file_id), str(version))

    return response
Esempio n. 4
0
def PUT(request, api_library, app):
    """
    PUT /file/:file_id

    Body parameters (JSON encoded):
        - name: (Optional) The user-visible name of the file to be created.
        - parent: (Optional) ID of the folder where the file or folder is going to be moved. If ID is
                    set to '0', it will be moved the top-level (root) folder.

    Update file metadata

    An application can update various attributes of a file by issuing an HTTP PUT request to the URL that
    represents the file resource. In addition, the app needs to provide as input, JSON that identifies the
    new attribute values for the file. Upon receiving the PUT request, the StackSync service examines the
    input and updates any of the attributes that have been modified.
    """

    try:
        _, _, file_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error("StackSync API: file_resource PUT: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id")

    try:
        params = json.loads(unicode(request.body, 'iso-8859-15'))
    except:
        app.logger.error('StackSync API: file_resource PUT: status: %s path info: %s', str(404), request.path_info)
        return create_error_response(400, "Could not decode body parameters.")

    try:
        parent = params['parent']
    except KeyError:
        parent = None
    try:
        name = params['name']
    except KeyError:
        name = None

    app.logger.info('StackSync API: file_resource PUT: path info: %s', request.path_info)
    user_id = request.environ["stacksync_user_id"]

    message = api_library.put_metadata(user_id, file_id, name, parent)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: file_resource PUT: error updateing file in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 5
0
def POST(request, api_library, app):
    """
    POST /folder/:folder_id

    Create a folder

    An application can create a folder by issuing an HTTP POST request to the URL of the containing folder
    resource. In addition, the application needs to provide as input, JSON that identifies the display name
    of the folder to be created.
    """

    try:
        args = json.loads(unicode(request.body, 'iso-8859-15'))
    except:
        app.logger.error(
            "StackSync API: folder_resource POST: Could not parse body parameters. Body %s",
            str(request.body))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder_id")

    try:
        parent = args['parent']
    except KeyError:
        parent = None
    try:
        name = args['name']
    except KeyError:
        name = None

    app.logger.info(
        'StackSync API: folder_resource POST: path info: %s, body=%s' %
        (str(request.path_info), request.body))

    if not name:
        app.logger.error(
            "StackSync API: folder_resource POST: error: 400. description: Folder name not set."
        )
        return create_error_response(400, "Folder name not set.")

    user_id = request.environ["stacksync_user_id"]

    message = api_library.new_folder(user_id, name, parent)

    response = create_response(message, status_code=201)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: folder_resource POST: error creating folder in StackSync Server: %s.",
            str(response.status_int))
    return response
Esempio n. 6
0
def DELETE(request, api_library, app):
    """
    DELETE /folder/:folder_id

    Delete a folder

    An application can permanently delete a folder by issuing an HTTP DELETE request to the URL of the
    folder resource. It's a good idea to precede DELETE requests like this with a caution note in your
    application's user interface.
    """

    try:
        _, _, folder_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error("StackSync API: folder_resource DELETE: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id")

    app.logger.info('StackSync API: folder_resource DELETE: path info: %s ', str(request.path_info))
    user_id = request.environ["stacksync_user_id"]

    message = api_library.delete_item(user_id, folder_id, is_folder=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: folder_resource DELETE: error deleting folder in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 7
0
    def upload_file_chunks(self, env, chunked_file, container):
        error = False
        self.app.logger.info('StackSync API: upload_file_chunks: container: %s', str(container))
        upload_chunks = []
        for i in range(len(chunked_file.chunks)):
            chunk_name = chunked_file.name_list[i-1]
            chunk_content = chunked_file.chunks[i-1]

            env_aux = env.copy()
            new_path = "/v1/" + env['stacksync_user_account'] + "/" + container + "/" + chunk_name
            del env_aux['HTTP_STACKSYNC_API']
            seg_req = make_pre_authed_request(env_aux, method='PUT', path=new_path, body=chunk_content,
                                              agent=str(container))

            seg_resp = seg_req.get_response(self.app)

            if not is_valid_status(seg_resp.status_int):
                self.app.logger.error('StackSync API: upload_file_chunks: error uploading chunk %s', chunk_name)
                error = True
                break
            upload_chunks.append(chunk_name)

        if error:
            self.app.logger.error(
                'StackSync API: upload_file_chunks: status: %s description: Error uploading chunks to storage backend',
                seg_resp.status)
            response = create_error_response(500, "Error uploading chunks to storage backend")
            self.remove_chunks(env, upload_chunks, container)

        else:
            response = HTTPCreated()

        return response
Esempio n. 8
0
    def remove_old_chunks(self, env, chunks_diff, container):
        error = False
        self.app.logger.info('StackSync API: remove old chunks: container: %s',
                             str(container))
        for chunk_name in chunks_diff:

            env_aux = env.copy()
            new_path = "/v1/" + env[
                'stacksync_user_account'] + "/" + container + "/" + str(
                    chunk_name)
            del env_aux['HTTP_STACKSYNC_API']
            seg_req = make_pre_authed_request(env_aux,
                                              method='DELETE',
                                              path=new_path,
                                              agent=str(container))

            seg_resp = seg_req.get_response(self.app)

            if not is_valid_status(seg_resp.status_int):
                self.app.logger.error(
                    'StackSync API: upload_file_chunks: error deleting old chunk %s',
                    str(chunk_name))
                error = True
                break

        if error:
            self.app.logger.error(
                'StackSync API: upload_file_chunks: status: %s description: Error uploading chunks to storage backend',
                seg_resp.status)
            response = create_error_response(
                500, "Error uploading chunks to storage backend")
        else:
            response = HTTPCreated()

        return response
Esempio n. 9
0
    def remove_old_chunks(self, env, chunks_diff, container):
        error = False
        self.app.logger.info('StackSync API: remove old chunks: container: %s', str(container))
        for chunk_name in chunks_diff:

            env_aux = env.copy()
            new_path = "/v1/" + env['stacksync_user_account'] + "/" + container + "/" + str(chunk_name)
            del env_aux['HTTP_STACKSYNC_API']
            seg_req = make_pre_authed_request(env_aux, method='DELETE', path=new_path,
                                              agent=str(container))

            seg_resp = seg_req.get_response(self.app)

            if not is_valid_status(seg_resp.status_int):
                self.app.logger.error('StackSync API: upload_file_chunks: error deleting old chunk %s', str(chunk_name))
                error = True
                break

        if error:
            self.app.logger.error(
                'StackSync API: upload_file_chunks: status: %s description: Error uploading chunks to storage backend',
                seg_resp.status)
            response = create_error_response(500, "Error uploading chunks to storage backend")
        else:
            response = HTTPCreated()

        return response
Esempio n. 10
0
def GET(request, api_library, app):
    """
    GET /folder/:folder_id

    Get folder metadata

    To retrieve information about a folder, an application submits an HTTP GET request to the folder
    resource that represents the folder. To get information about the root folder, users must set the
    ID to “0” (i.e. /folder/0).
    """

    try:
        _, _, folder_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error(
            "StackSync API: folder_resource GET: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder")

    app.logger.info('StackSync API: folder_resource GET: path info: %s ',
                    str(request.path_info))
    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_metadata(user_id, folder_id, is_folder=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: folder_resource DELETE: error deleting folder in StackSync Server: %s.",
            str(response.status_int))
    return response
Esempio n. 11
0
def DELETE(request, api_library, app):
    """
    DELETE /folder/:folder_id

    Delete a folder

    An application can permanently delete a folder by issuing an HTTP DELETE request to the URL of the
    folder resource. It's a good idea to precede DELETE requests like this with a caution note in your
    application's user interface.
    """

    try:
        _, _, folder_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error(
            "StackSync API: folder_resource DELETE: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder_id")

    app.logger.info('StackSync API: folder_resource DELETE: path info: %s ',
                    str(request.path_info))
    user_id = request.environ["stacksync_user_id"]

    message = api_library.delete_item(user_id, folder_id, is_folder=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: folder_resource DELETE: error deleting folder in StackSync Server: %s.",
            str(response.status_int))
    return response
Esempio n. 12
0
def GET(request, api_library, app):
    """
    GET /folder/:folder_id

    Get folder metadata

    To retrieve information about a folder, an application submits an HTTP GET request to the folder
    resource that represents the folder. To get information about the root folder, users must set the
    ID to “0” (i.e. /folder/0).
    """

    try:
        _, _, folder_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error("StackSync API: folder_resource GET: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder")

    app.logger.info('StackSync API: folder_resource GET: path info: %s ', str(request.path_info))
    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_metadata(user_id, folder_id, is_folder=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: folder_resource DELETE: error deleting folder in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 13
0
def GET(request, api_library, app):
    """
    GET /file/:file_id

    Get file's metadata

    To retrieve information about a file, an application submits an HTTP GET request to the file
    resource that represents the file.
    """

    try:
        _, _, file_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error("StackSync API: file_resource GET: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id")

    app.logger.info('StackSync API: file_resource GET: path info: %s', request.path_info)
    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_metadata(user_id, file_id, is_folder=False)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: file_resource GET: Error getting file metadata from StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 14
0
def POST(request, api_library, app):
    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error("StackSync API: share_resource POST: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id/unsahre")

    content = request.body
    content = json.loads(content)
    if len(content) > 0:
        message = api_library.unshare_folder(request.environ["stacksync_user_id"], folder_id, content)
        response = create_response(message, status_code=201)
        return response
    else:
        app.logger.error("StackSync API: share_resource POST: Bad request - Empty content")
        return create_error_response(400, "Any email to share folder")
Esempio n. 15
0
def POST(request, api_library, app):
    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error("StackSync API: share_resource POST: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id/sahre")

    content = request.body
    content = json.loads(content)
    if len(content) > 0:
        message = api_library.share_folder(request.environ["stacksync_user_id"], folder_id, content)
        response = create_response(message, status_code=201)
        return response
    else:
        app.logger.error("StackSync API: share_resource POST: Bad request - Empty content")
        return create_error_response(400, "No addressee found.")
Esempio n. 16
0
def POST(request, api_library, app):
    """
    POST /folder/:folder_id

    Create a folder

    An application can create a folder by issuing an HTTP POST request to the URL of the containing folder
    resource. In addition, the application needs to provide as input, JSON that identifies the display name
    of the folder to be created.
    """

    try:
        args = json.loads(unicode(request.body, 'iso-8859-15'))
    except:
        app.logger.error("StackSync API: folder_resource POST: Could not parse body parameters. Body %s",
                         str(request.body))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id")

    try:
        parent = args['parent']
    except KeyError:
        parent = None
    try:
        name = args['name']
    except KeyError:
        name = None

    app.logger.info(
        'StackSync API: folder_resource POST: path info: %s, body=%s' % (str(request.path_info), request.body))

    if not name:
        app.logger.error("StackSync API: folder_resource POST: error: 400. description: Folder name not set.")
        return create_error_response(400, "Folder name not set.")

    user_id = request.environ["stacksync_user_id"]

    message = api_library.new_folder(user_id, name, parent)

    response = create_response(message, status_code=201)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: folder_resource POST: error creating folder in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 17
0
def DELETE(request, api_library, app):
    """
    DELETE /file/:file_id

    Delete a file

    An application can delete a file by issuing an HTTP DELETE request to the URL of the file resource.
    It's a good idea to precede DELETE requests like this with a caution note in your application's user
    interface.
    """

    try:
        _, _, file_id = split_path(request.path, 3, 3, False)
    except:
        app.logger.error("StackSync API: file_resource DELETE: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id")

    app.logger.info('StackSync API: file_resource DELETE: path info: %s', request.path_info)
    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_metadata(user_id, file_id, is_folder=False, include_chunks=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource DELETE: status code: %s. body: %s", str(response.status_int),
                         str(response.body))
        return response
    workspace_info = api_library.get_workspace_info(user_id, file_id)

    response = create_response(workspace_info, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource PUT: status code: %s. body: %s", str(response.status_int),
                             str(response.body))
        return response

    workspace_info = json.loads(workspace_info)
    data_handler = DataHandler(app)
    file_metadata = json.loads(message)
    container_name = workspace_info['swift_container']
    response = data_handler.remove_old_chunks(request.environ, file_metadata['chunks'], container_name)
    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource DELETE: status code: %s. body: %s", str(response.status_int),
                         str(response.body))
        return response

    message_delete = api_library.delete_item(user_id, file_id, is_folder=False)

    response = create_response(message_delete, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: file_resource DELETE: error deleting file in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 18
0
def GET(request, api_library, app):
    """
    GET /file/:file_id/[versions|version/:version_id]

    Get file versions and version metadata

    To retrieve information about a file version, an application submits an HTTP GET request
    to the file version resource.
    """

    try:    
        _, _, file_id, _, version = split_path(request.path, 4, 5, False)
    except:
        app.logger.error("StackSync API: file_resource DELETE: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id")

        app.logger.info('StackSync API: versions_resource GET: error: 400, path info: %s ', str(request.path_info))
        return create_error_response(400, "Some problem with path.")

    app.logger.info('StackSync API: versions_resource GET: path info: %s ', str(request.path_info))

    user_id = request.environ["stacksync_user_id"]

    if not version:
        # if no version is given, return the list of versions
        message = api_library.get_versions(user_id, file_id)
        response = create_response(message, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: versions_resource GET: error getting versions of file: %s.",
                             str(file_id))
    else:
        # if a version is given, return metadata about that specific version
        message = api_library.get_metadata(user_id, file_id, specific_version=version, is_folder=False)
        response = create_response(message, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: versions_resource GET: error getting version of file %s and version %s.",
                             str(file_id), str(version))

    return response
Esempio n. 19
0
def GET(request, api_library, app):
    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error("StackSync API: share_resource GET: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id/members")

    message = api_library.get_folder_members(request.environ["stacksync_user_id"], folder_id)
    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: folder members GET: error getting folder members in StackSync Server: %s.",
                         str(response.status_int))
    return response
Esempio n. 20
0
def GET(request, api_library, app):
    """
    GET /folder/:file_id/contents.

    Query parameters:
        - include_deleted: (Optional) False by default. If it is set to true, then response will
                            include metadata of deleted objects.

    Get folder content metadata

    To retrieve information about a folder, an application submits an HTTP GET request
    to the folder resource that represents the folder. To get information about the root
    folder, users must set the folder ID to “0” (i.e. /folder/0/contents).
    """

    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error(
            "StackSync API: contents_resource GET: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder_id/contents")

    try:
        include_deleted = request.params.get('include_deleted')
        if not include_deleted:
            include_deleted = False
    except:
        include_deleted = False

    app.logger.info('StackSync API: contents_resource GET: path info: %s ',
                    str(request.path_info))

    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_folder_contents(user_id, folder_id,
                                              include_deleted)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: file_resource POST: error updating data in StackSync Server: %s. body: %s",
            str(response.status_int), str(response.body))

    return response
Esempio n. 21
0
def GET(request, api_library, app):
    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error(
            "StackSync API: share_resource GET: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /folder/:folder_id/members")

    message = api_library.get_folder_members(
        request.environ["stacksync_user_id"], folder_id)
    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: folder members GET: error getting folder members in StackSync Server: %s.",
            str(response.status_int))
    return response
Esempio n. 22
0
def GET(request, api_library, app):
    """
    GET /folder/:file_id/contents.

    Query parameters:
        - include_deleted: (Optional) False by default. If it is set to true, then response will
                            include metadata of deleted objects.

    Get folder content metadata

    To retrieve information about a folder, an application submits an HTTP GET request
    to the folder resource that represents the folder. To get information about the root
    folder, users must set the folder ID to “0” (i.e. /folder/0/contents).
    """

    try:
        _, _, folder_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error("StackSync API: contents_resource GET: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /folder/:folder_id/contents")

    try:
        include_deleted = request.params.get('include_deleted')
        if not include_deleted:
            include_deleted = False
    except:
        include_deleted = False

    app.logger.info('StackSync API: contents_resource GET: path info: %s ', str(request.path_info))

    user_id = request.environ["stacksync_user_id"]

    message = api_library.get_folder_contents(user_id, folder_id, include_deleted)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: file_resource POST: error updating data in StackSync Server: %s. body: %s",
                         str(response.status_int),
                         str(response.body))

    return response
Esempio n. 23
0
    def upload_file_chunks(self, env, chunked_file, container):
        error = False
        self.app.logger.info(
            'StackSync API: upload_file_chunks: container: %s', str(container))
        upload_chunks = []
        for i in range(len(chunked_file.chunks)):
            chunk_name = chunked_file.name_list[i - 1]
            chunk_content = chunked_file.chunks[i - 1]

            env_aux = env.copy()
            new_path = "/v1/" + env[
                'stacksync_user_account'] + "/" + container + "/" + chunk_name
            del env_aux['HTTP_STACKSYNC_API']
            seg_req = make_pre_authed_request(env_aux,
                                              method='PUT',
                                              path=new_path,
                                              body=chunk_content,
                                              agent=str(container))

            seg_resp = seg_req.get_response(self.app)

            if not is_valid_status(seg_resp.status_int):
                self.app.logger.error(
                    'StackSync API: upload_file_chunks: error uploading chunk %s',
                    chunk_name)
                error = True
                break
            upload_chunks.append(chunk_name)

        if error:
            self.app.logger.error(
                'StackSync API: upload_file_chunks: status: %s description: Error uploading chunks to storage backend',
                seg_resp.status)
            response = create_error_response(
                500, "Error uploading chunks to storage backend")
            self.remove_chunks(env, upload_chunks, container)

        else:
            response = HTTPCreated()

        return response
Esempio n. 24
0
def GET(request, api_library, app):
    """
    GET /file/:file_id/data

    Download file data

    To retrieve file data, an application submits an HTTP GET request to the file data resource that
    represents the data for the file.
    """
    try:
        _, _, file_id, _, version, _ = split_path(request.path, 4, 6, False)
    except:
        app.logger.error(
            "StackSync API: data_resource GET: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400,
            "Wrong resource path. Expected /file/:file_id/data[/version/:version_id]]"
        )

    app.logger.info('StackSync API: data_resource GET: path info: %s ',
                    str(request.path_info))

    user_id = request.environ["stacksync_user_id"]
    metadata = api_library.get_metadata(user_id,
                                        file_id,
                                        include_chunks=True,
                                        specific_version=version,
                                        is_folder=False)
    response = create_response(metadata, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: data_resource GET: status code: %s. body: %s",
            str(response.status_int), str(response.body))
        return response

    metadata = json.loads(metadata)

    data_handler = DataHandler(app)

    workspace_info = api_library.get_workspace_info(user_id, file_id)
    response = create_response(workspace_info, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: data_resource GET: status code: %s. body: %s",
            str(response.status_int), str(response.body))
        return response

    workspace_info = json.loads(workspace_info)
    container_name = workspace_info['swift_container']
    print 'chunks to retrieve', metadata['chunks']
    file_compress_content, status = data_handler.get_chunks(
        request.environ, metadata['chunks'], container_name)

    if is_valid_status(status):
        if len(file_compress_content) > 0:
            joined_file = BuildFile("", file_compress_content)
            joined_file.join()
            headers = {'Content-Type': metadata['mimetype']}
            return HTTPOk(body=joined_file.content, headers=headers)
        elif len(metadata['chunks']) == 0:
            return HTTPOk(body='')
        else:
            app.logger.error(
                "StackSync API: data_resource GET: Unexpected case. File_id: %s.",
                str(file_id))
            return create_error_response(
                500,
                "Could not retrieve file. Please contact an administrator.")
    else:
        app.logger.error(
            "StackSync API: data_resource GET: Cannot retrieve chunks. File_id: %s. Status: %s",
            str(file_id), str(status))
        return create_error_response(
            status, "Cannot retrieve chunks from storage backend.")
Esempio n. 25
0
def PUT(request, api_library, app):
    """
    PUT /file/:file_id/data

    Upload file data

    An application can upload data to a file by issuing an HTTP PUT request to the file data resource
    that represents the data for the file. The file binary will be sent in the request body.
    Uploading data to a file creates a new file version in the StackSync datastore and associates the
    uploaded data with the newly created file version.
    """
    content = request.body
    try:
        _, _, file_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error(
            "StackSync API: data_resource PUT: Wrong resource path: %s path_info: %s",
            str(400), str(request.path_info))
        return create_error_response(
            400, "Wrong resource path. Expected /file/:file_id/data")

    app.logger.info(
        'StackSync API: data_resource PUT: path info: %s content length: %i ',
        str(request.path_info), len(content))

    user_id = request.environ["stacksync_user_id"]

    # We look up the name of file, and full path, to update it.
    #TODO: addChunks true
    message = api_library.get_metadata(user_id,
                                       file_id,
                                       is_folder=False,
                                       include_chunks=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: data_resource PUT: status code: %s. body: %s",
            str(response.status_int), str(response.body))
        return response

    if len(content) > 0:
        file_metadata = json.loads(message)
        # get the workspace info (includes the container) from the file_id
        workspace_info = api_library.get_workspace_info(user_id, file_id)

        response = create_response(workspace_info, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error(
                "StackSync API: data_resource PUT: status code: %s. body: %s",
                str(response.status_int), str(response.body))
            return response

        workspace_info = json.loads(workspace_info)
        old_chunks = file_metadata['chunks']
        app.logger.info("StackSync API: old_chunks: %s", old_chunks)
        container_name = workspace_info['swift_container']

        #Get the quota information
        quota_limit = long(workspace_info['quota_limit'])
        quota_used = long(workspace_info['quota_used'])
        old_file_size = long(file_metadata['size'])

        #check if the new file exceed the quota limit
        quota_used = quota_used - old_file_size
        quota_used_after_put = quota_used + long(len(content))
        if (quota_used_after_put > quota_limit):
            return create_error_response(413, "Upload exceeds quota.")

        chunked_file = BuildFile(content, [])
        chunked_file.separate(file_id)
        chunks_to_remove = list(set(old_chunks) - set(chunked_file.name_list))
        data_handler = DataHandler(app)

        #upload new chunks
        chunks_to_upload = list(set(chunked_file.name_list) - set(old_chunks))
        chunks_already_uploaded = list(
            set(chunked_file.name_list) - set(chunks_to_upload))

        chunks = list(chunked_file.name_list)

        for chunk_name in chunks_already_uploaded:
            index = chunked_file.name_list.index(chunk_name)
            del chunked_file.name_list[index]
            del chunked_file.chunks[index]
        response = data_handler.upload_file_chunks(request.environ,
                                                   chunked_file,
                                                   container_name)

        if not is_valid_status(response.status_int):
            app.logger.error(
                "StackSync API: data_resource PUT: error uploading file chunks: %s path info: %s",
                str(response.status), str(request.path_info))
            return create_error_response(
                500, "Could not upload chunks to storage backend.")

        checksum = str((zlib.adler32(content) & 0xffffffff))
        file_size = str(len(content))
        mimetype = magic.from_buffer(content, mime=True)

    else:
        #Empty body
        chunks = []
        checksum = 0
        file_size = 0
        mimetype = 'inode/x-empty'

    new_version_response = api_library.update_data(user_id, file_id, checksum,
                                                   file_size, mimetype, chunks)

    response = create_response(new_version_response, status_code=201)
    if not is_valid_status(response.status_int):
        app.logger.error(
            "StackSync API: data_resource PUT: error updating data in StackSync Server: %s. body: %s",
            str(response.status_int), str(response.body))
    else:
        #delete old chunks
        response = data_handler.remove_old_chunks(request.environ,
                                                  chunks_to_remove,
                                                  container_name)
        if not is_valid_status(response.status_int):
            app.logger.error(
                "StackSync API: data_resource PUT: error uploading file chunks: %s path info: %s",
                str(response.status), str(request.path_info))
            return create_error_response(
                500, "Could not upload chunks to storage backend.")

    return response
Esempio n. 26
0
def POST(request, api_library, app):
    """
    POST /file

    Query arguments:
        - name: The user-visible name of the file to be created.
        - parent: (Optional) ID of the folder where the file is going to be created.
                    If no ID is given or if ID is '0', it will use the top-level (root) folder.

    Create a file

    An application can create a file by issuing an HTTP POST request. The application needs to provide
    the file binary in the body and the file name as a query argument. Optionally, it can also provide
    the parent argument to locate the file in a specific folder. Otherwise, the file will be placed in
    the root folder.
    """

    try:
        params = request.params
        content = request.body
    except:
        app.logger.error('StackSync API: file_resource POST: Could not obtain input parameters')
        return create_error_response(400, "Could not obtain input parameters.")

    try:
        parent = params.get('parent')
    except:
        parent = None
    try:
        name = params.get('name')
    except:
        name = None

    if not name:
        app.logger.error('StackSync API: file_resource POST: Invalid file name.')
        return create_error_response(400, "Invalid file name.")

    user_id = request.environ["stacksync_user_id"]

    if len(content) > 0:
        app.logger.info('StackSync API: file_resource POST: content_length: %s name: %s parent: %s', str(len(content)),
                        str(name), str(parent))

        workspace_info = api_library.get_workspace_info(user_id, parent)
        response = create_response(workspace_info, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: file_resource POST: status code: %s. body: %s", str(response.status_int),
                             str(response.body))
            return response

        workspace_info = json.loads(workspace_info)
        container_name = workspace_info['swift_container']
        #Take the quota information
        quota_used = long(workspace_info['quota_used'])
        quota_limit = long(workspace_info['quota_limit'])

        #check if the new file exced the quota limit
        quota_used_after_put = quota_used + long(len(content))
        if (quota_used_after_put > quota_limit):
            return create_error_response(413, "Upload exceeds quota.")
            
        chunked_file = BuildFile(content, [])
        tmp_file_id = str(random.getrandbits(64))
        chunked_file.separate(tmp_file_id)

        data_handler = DataHandler(app)

        response = data_handler.upload_file_chunks(request.environ, chunked_file, container_name)

        chunks = chunked_file.name_list
        checksum = str((zlib.adler32(content) & 0xffffffff))
        file_size = len(content)
        mimetype = magic.from_buffer(content, mime=True)

        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: file_resource POST: error uploading file chunks: %s path info: %s",
                             str(response.status),
                             str(request.path_info))
            return response

    else:
        # Empty body
        checksum = 0
        file_size = 0
        mimetype = 'inode/x-empty'
        chunks = []

    message_new_version = api_library.new_file(user_id, name, parent, checksum, file_size, mimetype, chunks)
    response = create_response(message_new_version, status_code=201)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: file_resource POST: error updating data in StackSync Server: %s. body: %s",
                         str(response.status_int),
                         str(response.body))

    return response
Esempio n. 27
0
def PUT(request, api_library, app):
    """
    PUT /file/:file_id/data

    Upload file data

    An application can upload data to a file by issuing an HTTP PUT request to the file data resource
    that represents the data for the file. The file binary will be sent in the request body.
    Uploading data to a file creates a new file version in the StackSync datastore and associates the
    uploaded data with the newly created file version.
    """
    content = request.body
    try:
        _, _, file_id, _ = split_path(request.path, 4, 4, False)
    except:
        app.logger.error("StackSync API: data_resource PUT: Wrong resource path: %s path_info: %s", str(400),
                         str(request.path_info))
        return create_error_response(400, "Wrong resource path. Expected /file/:file_id/data")

    app.logger.info('StackSync API: data_resource PUT: path info: %s content length: %i ', str(request.path_info),
                    len(content))

    user_id = request.environ["stacksync_user_id"]

    # We look up the name of file, and full path, to update it.
    #TODO: addChunks true
    message = api_library.get_metadata(user_id, file_id, is_folder=False, include_chunks=True)

    response = create_response(message, status_code=200)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource PUT: status code: %s. body: %s", str(response.status_int),
                         str(response.body))
        return response

    if len(content) > 0:
        file_metadata = json.loads(message)
        # get the workspace info (includes the container) from the file_id
        workspace_info = api_library.get_workspace_info(user_id, file_id)

        response = create_response(workspace_info, status_code=200)
        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: data_resource PUT: status code: %s. body: %s", str(response.status_int),
                             str(response.body))
            return response

        workspace_info = json.loads(workspace_info)
        old_chunks = file_metadata['chunks']
        app.logger.info("StackSync API: old_chunks: %s", old_chunks)
        container_name = workspace_info['swift_container']

        #Get the quota information
        quota_limit = long(workspace_info['quota_limit'])
        quota_used = long(workspace_info['quota_used'])
        old_file_size = long(file_metadata['size'])

        #check if the new file exceed the quota limit
        quota_used = quota_used - old_file_size
        quota_used_after_put = quota_used + long(len(content))
        if (quota_used_after_put > quota_limit):
            return create_error_response(413, "Upload exceeds quota.")

        chunked_file = BuildFile(content, [])
        chunked_file.separate(file_id)
        chunks_to_remove = list(set(old_chunks) - set(chunked_file.name_list))
        data_handler = DataHandler(app)

        #upload new chunks
        chunks_to_upload = list(set(chunked_file.name_list)-set(old_chunks))
        chunks_already_uploaded =  list(set(chunked_file.name_list)-set(chunks_to_upload))

        chunks = list(chunked_file.name_list)

        for chunk_name in chunks_already_uploaded:
            index = chunked_file.name_list.index(chunk_name)
            del chunked_file.name_list[index]
            del chunked_file.chunks[index]
        response = data_handler.upload_file_chunks(request.environ, chunked_file, container_name)

        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: data_resource PUT: error uploading file chunks: %s path info: %s",
                             str(response.status),
                             str(request.path_info))
            return create_error_response(500, "Could not upload chunks to storage backend.")

        checksum = str((zlib.adler32(content) & 0xffffffff))
        file_size = str(len(content))
        mimetype = magic.from_buffer(content, mime=True)

    else:
        #Empty body
        chunks = []
        checksum = 0
        file_size = 0
        mimetype = 'inode/x-empty'

    new_version_response = api_library.update_data(user_id, file_id, checksum, file_size, mimetype, chunks)

    response = create_response(new_version_response, status_code=201)
    if not is_valid_status(response.status_int):
        app.logger.error("StackSync API: data_resource PUT: error updating data in StackSync Server: %s. body: %s",
                         str(response.status_int),
                         str(response.body))
    else:
        #delete old chunks
        response = data_handler.remove_old_chunks(request.environ, chunks_to_remove, container_name)
        if not is_valid_status(response.status_int):
            app.logger.error("StackSync API: data_resource PUT: error uploading file chunks: %s path info: %s",
                             str(response.status),
                             str(request.path_info))
            return create_error_response(500, "Could not upload chunks to storage backend.")

    return response