Skip to content

Commit 93b73fc

Browse files
authored
Merge pull request #87 from CenterForOpenScience/dev
v0.2.2
2 parents 68e29f3 + 59aecf2 commit 93b73fc

26 files changed

+742
-190
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: osfr
22
Title: R Interface to OSF
3-
Version: 0.2.1
3+
Version: 0.2.2
44
Authors@R: c(
55
person("Aaron", "Wolen",, "[email protected]", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0003-2542-2202")),

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ S3method(osf_ls_nodes,osf_tbl_node)
1111
S3method(osf_ls_nodes,osf_tbl_user)
1212
S3method(osf_mkdir,osf_tbl_file)
1313
S3method(osf_mkdir,osf_tbl_node)
14+
S3method(osf_mv,osf_tbl_file)
1415
S3method(osf_open,character)
1516
S3method(osf_open,default)
1617
S3method(osf_open,osf_id)
1718
S3method(osf_open,osf_tbl)
1819
S3method(osf_open,osf_tbl_file)
20+
S3method(osf_rm,osf_tbl_file)
1921
S3method(osf_rm,osf_tbl_node)
2022
S3method(osf_upload,osf_tbl_file)
2123
S3method(osf_upload,osf_tbl_node)
@@ -29,6 +31,7 @@ export(osf_download)
2931
export(osf_ls_files)
3032
export(osf_ls_nodes)
3133
export(osf_mkdir)
34+
export(osf_mv)
3235
export(osf_open)
3336
export(osf_retrieve_file)
3437
export(osf_retrieve_node)

NEWS.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# osfr 0.2.2
2+
3+
## New functions
4+
5+
* `osf_mv()` to move files and directories to a new project, component, or
6+
subdirectory
7+
8+
## New features
9+
10+
* `osf_rm()` can now delete files and directories
11+
12+
## Minor improvements and fixes
13+
14+
* Restructured tests to better handle environments in which `OSF_PAT` and/or `OSF_SERVER` are not defined
15+
116
# osfr 0.2.1
217

318
* Minor tweaks to the website

R/api-client-osf.R

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ user_agent <- function(agent = "osfr") {
2626

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

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

4749
# OSF API request functions -----------------------------------------------
4850

49-
.osf_request <- function(method, path, query = list(), body = NULL, verbose = FALSE, ...) {
51+
.osf_request <-
52+
function(method,
53+
path,
54+
query = list(),
55+
body = NULL,
56+
verbose = FALSE,
57+
...) {
58+
5059
method <- match.arg(method, c("get", "put", "patch", "post", "delete"))
5160
cli <- .osf_cli()
5261
method <- cli[[method]]
5362
method(path, query, body = body, ...)
5463
}
5564

5665
# TODO: .osf_request and .osf_paginated_request returns should be consistent
57-
.osf_paginated_request <- function(method, path, query = list(), n_max = 100, verbose = FALSE) {
66+
.osf_paginated_request <-
67+
function(method,
68+
path,
69+
query = list(),
70+
n_max = 100,
71+
verbose = FALSE) {
72+
5873
items <- list()
5974
i <- 1
6075
retrieved <- 0
@@ -72,7 +87,9 @@ user_agent <- function(agent = "osfr") {
7287
items <- c(items, out$data)
7388

7489
if (verbose && n_max > 10) {
75-
if (i == 1) message(sprintf("Retrieving %i of %i available items:", n_max, total))
90+
if (i == 1) {
91+
message(sprintf("Retrieving %i of %i available items:", n_max, total))
92+
}
7693
message(sprintf("..retrieved %i items", retrieved), appendLF = TRUE)
7794
}
7895

R/api-client-wb.R

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
#' a trailing flash when referring to a folder
99
#'
1010
#' @noRd
11-
.wb_api_path <- function(id, fid = NULL, provider = "osfstorage", type = "folder") {
11+
.wb_api_path <-
12+
function(id,
13+
fid = NULL,
14+
provider = "osfstorage",
15+
type = "folder") {
16+
1217
type <- match.arg(type, c("folder", "file"))
1318
api_v <- floor(.wb_api_version)
1419
if (is.null(fid)) {
@@ -51,8 +56,15 @@
5156

5257
# Waterbutler request functions -------------------------------------------
5358

54-
.wb_request <- function(method, path, query = list(), body = NULL, verbose = FALSE, ...) {
55-
method <- match.arg(method, c("get", "put", "patch", "delete"))
59+
.wb_request <-
60+
function(method,
61+
path,
62+
query = list(),
63+
body = NULL,
64+
verbose = FALSE,
65+
...) {
66+
67+
method <- match.arg(method, c("get", "put", "patch", "post", "delete"))
5668
cli <- .wb_cli()
5769
method <- cli[[method]]
5870
method(path, query, body = body, ...)

R/api-endpoints-wb.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
type <- match.arg(type, c("file", "folder"))
6060
query <- list()
6161
if (zip) query$zip <- ""
62-
res <- .wb_request("get", .wb_api_path(id, fid, type = type), query, disk = path)
62+
api_path <- .wb_api_path(id, fid, type = type)
63+
res <- .wb_request("get", api_path, query, disk = path)
6364
if (res$status_code == 200) return(TRUE)
6465
if (res$status_code == 404) {
6566
msg <- sprintf("The requested %s (%s) could not be found in node `%s`",

R/osf_create.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ osf_create_component <-
7676
category = NULL) {
7777

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

8282
out <- .osf_node_create(

R/osf_ls_files.R

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ osf_ls_files.osf_tbl_node <-
5353
verbose = FALSE) {
5454

5555
x <- make_single(x)
56-
.osf_list_files(x, path, type, pattern, n_max, verbose)
56+
57+
if (!is.null(path) && path != ".") {
58+
leaf_dir <- recurse_path(x, path, missing_action = "error", verbose)
59+
return(osf_ls_files(leaf_dir, path = ".", type, pattern, n_max, verbose))
60+
}
61+
62+
.osf_list_files(x, type, pattern, n_max, verbose)
5763
}
5864

5965
#' @export
@@ -69,33 +75,31 @@ osf_ls_files.osf_tbl_file <-
6975
if (is_osf_file(x)) {
7076
abort("Listing an `osf_tbl_file` requires a directory\n* `x` contains a file")
7177
}
72-
.osf_list_files(x, path, type, pattern, n_max, verbose)
78+
79+
# walk down path tree and replace x with the leaf directory
80+
if (!is.null(path) && path != ".") {
81+
x <- recurse_path(x, path, missing_action = "error", verbose = verbose)
82+
}
83+
84+
.osf_list_files(x, type, pattern, n_max, verbose)
7385
}
7486

7587

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

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

85-
# recurse if path contains subdirectories
86-
path <- path %||% "."
87-
if (path != ".") {
88-
path_root <- fs::path_split(path)[[1]][1]
89-
root_dir <- find_exact_match(x, name = path_root, type = "folder")
90-
if (nrow(root_dir) == 0) {
91-
abort(sprintf("Can't find path `%s` within `%s`", path, x$name))
92-
}
93-
94-
next_path <- fs::path_rel(path, path_root)
95-
res <- .osf_list_files(root_dir, next_path, type, pattern, n_max, verbose)
96-
return(as_osf_tbl(res, "osf_tbl_file"))
97-
}
98-
99103
res <- .osf_paginated_request(
100104
method = "get",
101105
path = api_path,

R/osf_ls_nodes.R

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ osf_ls_nodes.osf_tbl_node <-
4141
n_max = 10,
4242
verbose = FALSE) {
4343
x <- make_single(x)
44-
out <- .osf_node_children(as_id(x), n_max, filter_nodes(pattern = pattern), verbose)
44+
45+
out <- .osf_node_children(
46+
id = as_id(x),
47+
n_max = n_max,
48+
query = filter_nodes(pattern = pattern),
49+
verbose = verbose
50+
)
51+
4552
raise_error(out)
4653
as_osf_tbl(out, "osf_tbl_node")
4754
}
@@ -53,7 +60,14 @@ osf_ls_nodes.osf_tbl_user <-
5360
n_max = 10,
5461
verbose = FALSE) {
5562
x <- make_single(x)
56-
out <- .osf_user_nodes(as_id(x), n_max, filter_nodes(pattern = pattern), verbose)
63+
64+
out <- .osf_user_nodes(
65+
id = as_id(x),
66+
n_max = n_max,
67+
query = filter_nodes(pattern = pattern),
68+
verbose = verbose
69+
)
70+
5771
raise_error(out)
5872
as_osf_tbl(out, "osf_tbl_node")
5973
}

R/osf_mkdir.R

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -36,58 +36,74 @@ osf_mkdir <- function(x, path, verbose = FALSE) {
3636

3737
#' @export
3838
osf_mkdir.osf_tbl_node <- function(x, path, verbose = FALSE) {
39-
4039
x <- make_single(x)
41-
id <- as_id(x)
40+
recurse_path(x, path, missing_action = "create", verbose)
41+
}
4242

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

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

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

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

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

76-
# does path root already exist?
72+
#' Recurse a directory path
73+
#'
74+
#' Given a path like 'root/subdir1/subdir2', this will retrieve each directory
75+
#' level from OSF and return the leaf directory. The `missing_action` argument
76+
#' determines what happens if an intermediate directory does not exist.
77+
#'
78+
#' @param x An `osf_tbl_node` or an `osf_tbl_file` with a directory.
79+
#' @param path A path of directories.
80+
#' @param missing_action Either `"error"` or `"create"` to create the missing
81+
#' directory.
82+
#' @noRd
83+
recurse_path <- function(x, path, missing_action = "error", verbose = FALSE) {
84+
missing_action <- match.arg(missing_action, c("error", "create"))
85+
7786
path_root <- fs::path_split(path)[[1]][1]
78-
items <- osf_ls_files(x, type = "folder", pattern = path_root)
79-
dir_root <- items[which(items$name == path_root), ]
87+
root_dir <- osf_ls_files(x, type = "folder", pattern = path_root)
8088

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

85-
dir_id <- gsub("/", "", res$data$attributes$path, fixed = TRUE)
86-
dir_root <- osf_retrieve_file(dir_id)
87-
msg <- sprintf("Created sub-directory '%s/' in directory '%s/'",
94+
# create the missing directory
95+
if (inherits(x, "osf_tbl_node")) {
96+
root_dir <- .osf_mkdir(as_id(x), name = path_root)
97+
msg <- sprintf("Created directory '%s/' in node %s",
98+
path_root, as_id(x))
99+
} else {
100+
root_dir <- .osf_mkdir(get_parent_id(x), name = path_root, fid = as_id(x))
101+
msg <- sprintf("Created sub-directory '%s/' in directory '%s/'",
88102
path_root, x$name)
103+
}
104+
89105
} else {
90-
msg <- sprintf("Sub-directory '%s/' already exists in directory '%s/'",
106+
msg <- sprintf("Navigating to sub-directory '%s/' in '%s'",
91107
path_root, x$name)
92108
}
93109

@@ -96,9 +112,9 @@ osf_mkdir.osf_tbl_file <- function(x, path, verbose = FALSE) {
96112
# recurse to the next-level if there is a subfolder
97113
path_next <- fs::path_rel(path, path_root)
98114
if (path_next == ".") {
99-
out <- dir_root
115+
out <- root_dir
100116
} else {
101-
out <- osf_mkdir(dir_root, path_next, verbose)
117+
out <- Recall(root_dir, path_next, missing_action, verbose)
102118
}
103119
out
104120
}

0 commit comments

Comments
 (0)