Skip to content

Commit

Permalink
Merge pull request #87 from CenterForOpenScience/dev
Browse files Browse the repository at this point in the history
v0.2.2
  • Loading branch information
aaronwolen authored Jan 25, 2019
2 parents 68e29f3 + 59aecf2 commit 93b73fc
Show file tree
Hide file tree
Showing 26 changed files with 742 additions and 190 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: osfr
Title: R Interface to OSF
Version: 0.2.1
Version: 0.2.2
Authors@R: c(
person("Aaron", "Wolen",, "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-2542-2202")),
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ S3method(osf_ls_nodes,osf_tbl_node)
S3method(osf_ls_nodes,osf_tbl_user)
S3method(osf_mkdir,osf_tbl_file)
S3method(osf_mkdir,osf_tbl_node)
S3method(osf_mv,osf_tbl_file)
S3method(osf_open,character)
S3method(osf_open,default)
S3method(osf_open,osf_id)
S3method(osf_open,osf_tbl)
S3method(osf_open,osf_tbl_file)
S3method(osf_rm,osf_tbl_file)
S3method(osf_rm,osf_tbl_node)
S3method(osf_upload,osf_tbl_file)
S3method(osf_upload,osf_tbl_node)
Expand All @@ -29,6 +31,7 @@ export(osf_download)
export(osf_ls_files)
export(osf_ls_nodes)
export(osf_mkdir)
export(osf_mv)
export(osf_open)
export(osf_retrieve_file)
export(osf_retrieve_node)
Expand Down
15 changes: 15 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# osfr 0.2.2

## New functions

* `osf_mv()` to move files and directories to a new project, component, or
subdirectory

## New features

* `osf_rm()` can now delete files and directories

## Minor improvements and fixes

* Restructured tests to better handle environments in which `OSF_PAT` and/or `OSF_SERVER` are not defined

# osfr 0.2.1

* Minor tweaks to the website
Expand Down
25 changes: 21 additions & 4 deletions R/api-client-osf.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ user_agent <- function(agent = "osfr") {

headers <- list(
`User-Agent` = user_agent(),
`Accept-Header` = sprintf("application/vnd.api+json;version=%s", .osf_api_version)
`Accept-Header` = sprintf(
"application/vnd.api+json;version=%s",
.osf_api_version)
)

if (!is.null(pat)) {
Expand All @@ -46,15 +48,28 @@ user_agent <- function(agent = "osfr") {

# OSF API request functions -----------------------------------------------

.osf_request <- function(method, path, query = list(), body = NULL, verbose = FALSE, ...) {
.osf_request <-
function(method,
path,
query = list(),
body = NULL,
verbose = FALSE,
...) {

method <- match.arg(method, c("get", "put", "patch", "post", "delete"))
cli <- .osf_cli()
method <- cli[[method]]
method(path, query, body = body, ...)
}

# TODO: .osf_request and .osf_paginated_request returns should be consistent
.osf_paginated_request <- function(method, path, query = list(), n_max = 100, verbose = FALSE) {
.osf_paginated_request <-
function(method,
path,
query = list(),
n_max = 100,
verbose = FALSE) {

items <- list()
i <- 1
retrieved <- 0
Expand All @@ -72,7 +87,9 @@ user_agent <- function(agent = "osfr") {
items <- c(items, out$data)

if (verbose && n_max > 10) {
if (i == 1) message(sprintf("Retrieving %i of %i available items:", n_max, total))
if (i == 1) {
message(sprintf("Retrieving %i of %i available items:", n_max, total))
}
message(sprintf("..retrieved %i items", retrieved), appendLF = TRUE)
}

Expand Down
18 changes: 15 additions & 3 deletions R/api-client-wb.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
#' a trailing flash when referring to a folder
#'
#' @noRd
.wb_api_path <- function(id, fid = NULL, provider = "osfstorage", type = "folder") {
.wb_api_path <-
function(id,
fid = NULL,
provider = "osfstorage",
type = "folder") {

type <- match.arg(type, c("folder", "file"))
api_v <- floor(.wb_api_version)
if (is.null(fid)) {
Expand Down Expand Up @@ -51,8 +56,15 @@

# Waterbutler request functions -------------------------------------------

.wb_request <- function(method, path, query = list(), body = NULL, verbose = FALSE, ...) {
method <- match.arg(method, c("get", "put", "patch", "delete"))
.wb_request <-
function(method,
path,
query = list(),
body = NULL,
verbose = FALSE,
...) {

method <- match.arg(method, c("get", "put", "patch", "post", "delete"))
cli <- .wb_cli()
method <- cli[[method]]
method(path, query, body = body, ...)
Expand Down
3 changes: 2 additions & 1 deletion R/api-endpoints-wb.R
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
type <- match.arg(type, c("file", "folder"))
query <- list()
if (zip) query$zip <- ""
res <- .wb_request("get", .wb_api_path(id, fid, type = type), query, disk = path)
api_path <- .wb_api_path(id, fid, type = type)
res <- .wb_request("get", api_path, query, disk = path)
if (res$status_code == 200) return(TRUE)
if (res$status_code == 404) {
msg <- sprintf("The requested %s (%s) could not be found in node `%s`",
Expand Down
2 changes: 1 addition & 1 deletion R/osf_create.R
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ osf_create_component <-
category = NULL) {

if (missing(x) || !inherits(x, "osf_tbl_node"))
abort("`x` must be an `osf_tbl_node` referencing an existing project/component. ")
abort("`x` must be an `osf_tbl_node` referencing an existing project/component.")
if (missing(title)) abort("Must define a title for the new component.")

out <- .osf_node_create(
Expand Down
42 changes: 23 additions & 19 deletions R/osf_ls_files.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ osf_ls_files.osf_tbl_node <-
verbose = FALSE) {

x <- make_single(x)
.osf_list_files(x, path, type, pattern, n_max, verbose)

if (!is.null(path) && path != ".") {
leaf_dir <- recurse_path(x, path, missing_action = "error", verbose)
return(osf_ls_files(leaf_dir, path = ".", type, pattern, n_max, verbose))
}

.osf_list_files(x, type, pattern, n_max, verbose)
}

#' @export
Expand All @@ -69,33 +75,31 @@ osf_ls_files.osf_tbl_file <-
if (is_osf_file(x)) {
abort("Listing an `osf_tbl_file` requires a directory\n* `x` contains a file")
}
.osf_list_files(x, path, type, pattern, n_max, verbose)

# walk down path tree and replace x with the leaf directory
if (!is.null(path) && path != ".") {
x <- recurse_path(x, path, missing_action = "error", verbose = verbose)
}

.osf_list_files(x, type, pattern, n_max, verbose)
}


.osf_list_files <- function(x, path, type, pattern, n_max, verbose) {
#' Internal list files method
#'
#' This requires an API path to more easily support different storage providers
#' in the future when listing from a node.
#' @return An `osf_tbl_file`.
#' @noRd
.osf_list_files <- function(x, type, pattern, n_max, verbose) {

# manually construct path for nodes because the provided files endpoint is
# for listing storage providers
# manually construct the API path because the 'files' endpoint for nodes lists
# the enabled storage providers
api_path <- switch(class(x)[1],
osf_tbl_node = .osf_api_path(sprintf("nodes/%s/files/osfstorage/", as_id(x))),
osf_tbl_file = crul::url_parse(get_relation(x, "files"))$path
)

# recurse if path contains subdirectories
path <- path %||% "."
if (path != ".") {
path_root <- fs::path_split(path)[[1]][1]
root_dir <- find_exact_match(x, name = path_root, type = "folder")
if (nrow(root_dir) == 0) {
abort(sprintf("Can't find path `%s` within `%s`", path, x$name))
}

next_path <- fs::path_rel(path, path_root)
res <- .osf_list_files(root_dir, next_path, type, pattern, n_max, verbose)
return(as_osf_tbl(res, "osf_tbl_file"))
}

res <- .osf_paginated_request(
method = "get",
path = api_path,
Expand Down
18 changes: 16 additions & 2 deletions R/osf_ls_nodes.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,14 @@ osf_ls_nodes.osf_tbl_node <-
n_max = 10,
verbose = FALSE) {
x <- make_single(x)
out <- .osf_node_children(as_id(x), n_max, filter_nodes(pattern = pattern), verbose)

out <- .osf_node_children(
id = as_id(x),
n_max = n_max,
query = filter_nodes(pattern = pattern),
verbose = verbose
)

raise_error(out)
as_osf_tbl(out, "osf_tbl_node")
}
Expand All @@ -53,7 +60,14 @@ osf_ls_nodes.osf_tbl_user <-
n_max = 10,
verbose = FALSE) {
x <- make_single(x)
out <- .osf_user_nodes(as_id(x), n_max, filter_nodes(pattern = pattern), verbose)

out <- .osf_user_nodes(
id = as_id(x),
n_max = n_max,
query = filter_nodes(pattern = pattern),
verbose = verbose
)

raise_error(out)
as_osf_tbl(out, "osf_tbl_node")
}
98 changes: 57 additions & 41 deletions R/osf_mkdir.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,58 +36,74 @@ osf_mkdir <- function(x, path, verbose = FALSE) {

#' @export
osf_mkdir.osf_tbl_node <- function(x, path, verbose = FALSE) {

x <- make_single(x)
id <- as_id(x)
recurse_path(x, path, missing_action = "create", verbose)
}

# does path root already exist?
path_root <- fs::path_split(path)[[1]][1]
items <- osf_ls_files(x, type = "folder", pattern = path_root)
dir_root <- items[which(items$name == path_root), ]
#' @export
osf_mkdir.osf_tbl_file <- function(x, path, verbose = FALSE) {
if (is_osf_file(x)) abort("Can't create directories within a file.")
x <- make_single(x)
recurse_path(x, path, missing_action = "create", verbose)
}

if (nrow(dir_root) == 0) {
res <- .wb_create_folder(id = id, name = path_root)
raise_error(res)
dir_id <- gsub("/", "", res$data$attributes$path, fixed = TRUE)
dir_root <- osf_retrieve_file(dir_id)
msg <- sprintf("Created directory '%s/' in node %s", path_root, id)
} else {
msg <- sprintf("Directory '%s/' already exists in node %s", path_root, id)
}

if (verbose) message(msg)
#' Create a single folder on OSF
#'
#' This wraps the create folder endpoint on Waterbutler but retrieves the newly
#' created directory from OSF because Waterbutler returns only a subset of the
#' information provided by OSF.
#'
#' @param id GUID for an OSF project or component
#' @param name Name of the new directory (note: this must be the name of a
#' single directory, not a path)
#' @param fid Optional, provide a Waterbutler folder ID to create the new folder
#' within the specified existing folder.
#' @noRd

# recurse to the next-level if there is a subfolder
path_next <- fs::path_rel(path, path_root)
if (path_next == ".") {
out <- dir_root
} else {
out <- osf_mkdir(dir_root, path_next, verbose)
}
out
.osf_mkdir <- function(id, name, fid = NULL) {
res <- .wb_create_folder(id, name, fid)
raise_error(res)
dir_id <- gsub("/", "", res$data$attributes$path, fixed = TRUE)
osf_retrieve_file(dir_id)
}

#' @export
osf_mkdir.osf_tbl_file <- function(x, path, verbose = FALSE) {
x <- make_single(x)
id <- as_id(x)
if (is_osf_file(x)) abort("Can't create directories within a file.")

# does path root already exist?
#' Recurse a directory path
#'
#' Given a path like 'root/subdir1/subdir2', this will retrieve each directory
#' level from OSF and return the leaf directory. The `missing_action` argument
#' determines what happens if an intermediate directory does not exist.
#'
#' @param x An `osf_tbl_node` or an `osf_tbl_file` with a directory.
#' @param path A path of directories.
#' @param missing_action Either `"error"` or `"create"` to create the missing
#' directory.
#' @noRd
recurse_path <- function(x, path, missing_action = "error", verbose = FALSE) {
missing_action <- match.arg(missing_action, c("error", "create"))

path_root <- fs::path_split(path)[[1]][1]
items <- osf_ls_files(x, type = "folder", pattern = path_root)
dir_root <- items[which(items$name == path_root), ]
root_dir <- osf_ls_files(x, type = "folder", pattern = path_root)

if (nrow(dir_root) == 0) {
res <- .wb_create_folder(id = get_parent_id(x), name = path_root, fid = id)
raise_error(res)
if (nrow(root_dir) == 0) {
if (missing_action == "error") {
abort(sprintf("Can't find directory '%s' in `%s`", path_root, x$name))
}

dir_id <- gsub("/", "", res$data$attributes$path, fixed = TRUE)
dir_root <- osf_retrieve_file(dir_id)
msg <- sprintf("Created sub-directory '%s/' in directory '%s/'",
# create the missing directory
if (inherits(x, "osf_tbl_node")) {
root_dir <- .osf_mkdir(as_id(x), name = path_root)
msg <- sprintf("Created directory '%s/' in node %s",
path_root, as_id(x))
} else {
root_dir <- .osf_mkdir(get_parent_id(x), name = path_root, fid = as_id(x))
msg <- sprintf("Created sub-directory '%s/' in directory '%s/'",
path_root, x$name)
}

} else {
msg <- sprintf("Sub-directory '%s/' already exists in directory '%s/'",
msg <- sprintf("Navigating to sub-directory '%s/' in '%s'",
path_root, x$name)
}

Expand All @@ -96,9 +112,9 @@ osf_mkdir.osf_tbl_file <- function(x, path, verbose = FALSE) {
# recurse to the next-level if there is a subfolder
path_next <- fs::path_rel(path, path_root)
if (path_next == ".") {
out <- dir_root
out <- root_dir
} else {
out <- osf_mkdir(dir_root, path_next, verbose)
out <- Recall(root_dir, path_next, missing_action, verbose)
}
out
}
Loading

0 comments on commit 93b73fc

Please sign in to comment.