Ejemplo n.º 1
0
def _status_data(upload_db_data: Upload,
                 upload_workspace: UploadWorkspace) -> dict:
    return {
        'upload_id': upload_db_data.upload_id,
        'upload_total_size': upload_workspace.total_upload_size,
        'upload_compressed_size': upload_workspace.content_package_size,
        'created_datetime': upload_db_data.created_datetime,
        'modified_datetime': upload_db_data.modified_datetime,
        'start_datetime': upload_db_data.lastupload_start_datetime,
        'completion_datetime': upload_db_data.lastupload_completion_datetime,
        'files': json.loads(upload_db_data.lastupload_file_summary),
        'errors': json.loads(upload_db_data.lastupload_logs),
        'upload_status': upload_db_data.lastupload_upload_status,
        'workspace_state': upload_db_data.state,
        'lock_state': upload_db_data.lock,
        'source_format': upload_workspace.source_format,
        'checksum': upload_workspace.content_checksum()
    }
Ejemplo n.º 2
0
def check_upload_content_exists(upload_id: int) -> Response:
    """
    Verify that the package content exists/is available.

    Parameters
    ----------
    upload_id : int
        The unique identifier for upload workspace.

    Returns
    -------
    Standard Response tuple containing response content, HTTP status, and HTTP headers.

    """
    try:
        upload_db_data: Optional[Upload] = uploads.retrieve(upload_id)
    except IOError:
        logger.error(
            "%s: ContentExistsCheck: There was a problem connecting "
            "to database.", upload_id)
        raise InternalServerError(UPLOAD_DB_CONNECT_ERROR)

    if upload_db_data is None:
        raise NotFound(UPLOAD_NOT_FOUND)

    logger.info("%s: Upload content summary request.", upload_id)
    upload_workspace = UploadWorkspace(upload_id)

    # This will potentially build content package if it does not exist
    checksum = upload_workspace.content_checksum()
    modified = ''
    size = 0

    # Double check package exists
    if upload_workspace.content_package_exists:
        modified = upload_workspace.content_package_modified
        size = upload_workspace.content_package_size
        return {}, status.OK, {
            'ETag': checksum,
            'Content-Length': size,
            'Last-Modified': modified
        }
    headers = {'ARXIV-OWNER': upload_db_data.owner_user_id, 'ETag': checksum}
    return {}, status.OK, headers
Ejemplo n.º 3
0
def get_upload_content(upload_id: int) -> Response:
    """
    Package up files for downloading as a compressed gzipped tar file.

    Parameters
    ----------
    upload_id : int
        The unique identifier for upload workspace.

    Returns
    -------
    Standard Response tuple containing compressed content, HTTP status, and HTTP headers.

    """
    try:
        upload_db_data: Optional[Upload] = uploads.retrieve(upload_id)
    except IOError:
        logger.error(
            "%s: ContentDownload: There was a problem connecting "
            "to database.", upload_id)
        raise InternalServerError(UPLOAD_DB_CONNECT_ERROR)

    if upload_db_data is None:
        raise NotFound(UPLOAD_NOT_FOUND)
    upload_workspace = UploadWorkspace(upload_id)
    checksum = upload_workspace.content_checksum()
    try:
        filepointer = upload_workspace.get_content()
    except FileNotFoundError as e:
        raise NotFound("No content in workspace") from e
    headers = {
        "Content-disposition": f"filename={filepointer.name}",
        'ETag': checksum,
        'ARXIV-OWNER': upload_db_data.owner_user_id
    }
    return filepointer, status.OK, headers
Ejemplo n.º 4
0
def client_delete_all_files(upload_id: int) -> Response:
    """
    Delete all files uploaded by client from specified workspace.

    This request is being received from API so we need to be extra careful.

    Parameters
    ----------
    upload_id : int
        The unique identifier for the upload_db_data in question.
    public_file_path: str
        relative path of file to be deleted.

    Returns
    -------
    dict
        Complete summary of upload processing.
    int
        An HTTP status code.
    dict
        Some extra headers to add to the response.

    """
    logger.info("%s: Deleting all uploaded files from this workspace.",
                upload_id)

    try:
        # Make sure we have an upload_db_data to work with
        upload_db_data: Optional[Upload] = uploads.retrieve(upload_id)

        if upload_db_data is None:
            # Invalid workspace identifier
            raise NotFound(UPLOAD_NOT_FOUND)
        if upload_db_data.state != Upload.ACTIVE:
            # Do we log anything for these requests
            raise Forbidden(UPLOAD_NOT_ACTIVE)
        if upload_db_data.lock == Upload.LOCKED:
            raise Forbidden(UPLOAD_WORKSPACE_LOCKED)

        # Create Upload object
        upload_workspace = UploadWorkspace(upload_id)

        upload_workspace.client_remove_all_files()

    except IOError:
        logger.error("%s: Delete all files request failed ", upload_id)
        raise InternalServerError(CANT_DELETE_ALL_FILES)
    except NotFound as nf:
        logger.info("%s: DeleteAllFiles: '%s'", upload_id, nf)
        raise
    except Forbidden as forb:
        logger.info("%s: Upload failed: '%s'.", upload_id, forb)
        raise forb
    except Exception as ue:
        logger.info(
            "Unknown error in delete all files. "
            " Add except clauses for '%s'. DO IT NOW!", ue)
        raise InternalServerError(UPLOAD_UNKNOWN_ERROR)

    response_data = _status_data(upload_db_data, upload_workspace)
    response_data.update({
        'reason': UPLOAD_DELETED_ALL_FILES,
        'checksum': upload_workspace.content_checksum()
    })  # Get rid of pylint error
    headers = {'ARXIV-OWNER': upload_db_data.owner_user_id}
    return response_data, status.OK, headers
Ejemplo n.º 5
0
def client_delete_file(upload_id: int, public_file_path: str) -> Response:
    """Delete a single file.

    This request is being received from API so we need to be extra careful.

    Parameters
    ----------
    upload_id : int
        The unique identifier for the upload_db_data in question.
    public_file_path: str
        relative path of file to be deleted.

    Returns
    -------
    dict
        Complete summary of upload processing.
    int
        An HTTP status code.
    dict
        Some extra headers to add to the response.

    """
    logger.info("%s: Delete file '%s'.", upload_id, public_file_path)

    try:
        # Make sure we have an upload_db_data to work with
        upload_db_data: Optional[Upload] = uploads.retrieve(upload_id)

        if upload_db_data is None:
            # Invalid workspace identifier
            raise NotFound(UPLOAD_NOT_FOUND)
        if upload_db_data.state != Upload.ACTIVE:
            # Do we log anything for these requests
            raise Forbidden(UPLOAD_NOT_ACTIVE)
        if upload_db_data.lock == Upload.LOCKED:
            raise Forbidden(UPLOAD_WORKSPACE_LOCKED)

        # Create Upload object
        upload_workspace = UploadWorkspace(upload_id)

        # Call routine that will do the actual work
        upload_workspace.client_remove_file(public_file_path)

    except IOError:
        logger.error("%s: Delete file request failed ", upload_id)
        raise InternalServerError(CANT_DELETE_FILE)
    except NotFound as nf:
        logger.info("%s: DeleteFile: %s", upload_id, nf)
        raise nf
    except SecurityError as secerr:
        logger.info("%s: %s", upload_id, secerr.description)
        # TODO: Should this be BadRequest or NotFound. I'm leaning towards
        # NotFound in order to provide as little feedback as posible to client.
        raise NotFound(UPLOAD_FILE_NOT_FOUND)
    except Forbidden as forb:
        logger.info("%s: Delete file forbidden: %s.", upload_id, forb)
        raise forb
    except Exception as ue:
        logger.info(
            "Unknown error in delete file. "
            " Add except clauses for '%s'. DO IT NOW!", ue)
        raise InternalServerError(UPLOAD_UNKNOWN_ERROR)

    response_data = _status_data(upload_db_data, upload_workspace)
    response_data.update({
        'reason': UPLOAD_DELETED_FILE,
        'checksum': upload_workspace.content_checksum()
    })  # Get rid of pylint errorT
    headers = {'ARXIV-OWNER': upload_db_data.owner_user_id}
    return response_data, status.OK, headers