Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get by itemid #157

Merged
merged 2 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# Microsoft365R 2.3.4.9000

## OneDrive/SharePoint

- Fix broken functionality for shared items in OneDrive/Sharepoint. In particular, this should allow using the MS365 backend with the pins package (#149/#129).
- The `list_shared_items`/`list_shared_files` method for drives now always returns a list of drive item objects, rather than a data frame. If the `info` argument is supplied with a value other than "items", a warning is issued.
- Add folder upload and download functionality for `ms_drive_item$upload()` and `download()`. Subfolders can also be transferred recursively, and optionally in parallel. There are also corresponding `ms_drive$upload_folder()` and `download_folder()` methods.
- Add the ability to use object IDs instead of file/folder paths in `ms_drive` methods, including getting, uploading and downloading. This can be useful since the object ID is immutable, whereas file paths can be changed. See `?ms_drive` for more details.

## Outlook

- Fix a bug in specifying multiple addresses in an email (#134, #151).

# Microsoft365R 2.3.4

Expand Down
82 changes: 47 additions & 35 deletions R/ms_drive.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,37 @@
#' - `do_operation(...)`: Carry out an arbitrary operation on the drive.
#' - `sync_fields()`: Synchronise the R object with the drive metadata in Microsoft Graph.
#' - `list_items(...), list_files(...)`: List the files and folders under the specified path. See 'File and folder operations' below.
#' - `download_file(src, dest, overwrite)`: Download a file.
#' - `download_folder(src, dest, overwrite, recursive, parallel)`: Download a folder.
#' - `download_file(src, srcid, dest, overwrite)`: Download a file.
#' - `download_folder(src, srcid, dest, overwrite, recursive, parallel)`: Download a folder.
#' - `upload_file(src, dest, blocksize)`: Upload a file.
#' - `upload_folder(src, dest, blocksize, recursive, parallel)`: Upload a folder.
#' - `create_folder(path)`: Create a folder.
#' - `open_item(path)`: Open a file or folder.
#' - `open_item(path, itemid)`: Open a file or folder.
#' - `create_share_link(...)`: Create a shareable link for a file or folder.
#' - `delete_item(path, confirm, by_item)`: Delete a file or folder. By default, ask for confirmation first. For personal OneDrive, deleting a folder will also automatically delete its contents; for business OneDrive or SharePoint document libraries, you may need to set `by_item=TRUE` to delete the contents first depending on your organisation's policies. Note that this can be slow for large folders.
#' - `get_item(path)`: Get an item representing a file or folder.
#' - `get_item_properties(path)`: Get the properties (metadata) for a file or folder.
#' - `set_item_properties(path, ...)`: Set the properties for a file or folder.
#' - `delete_item(path, itemid, confirm, by_item)`: Delete a file or folder. By default, ask for confirmation first. For personal OneDrive, deleting a folder will also automatically delete its contents; for business OneDrive or SharePoint document libraries, you may need to set `by_item=TRUE` to delete the contents first depending on your organisation's policies. Note that this can be slow for large folders.
#' - `get_item(path, itemid)`: Get an item representing a file or folder.
#' - `get_item_properties(path, itemid)`: Get the properties (metadata) for a file or folder.
#' - `set_item_properties(path, itemid, ...)`: Set the properties for a file or folder.
#' - `list_shared_items(...), list_shared_files(...)`: List the drive items shared with you. See 'Shared items' below.
#'
#' @section Initialization:
#' Creating new objects of this class should be done via the `get_drive` methods of the [`ms_graph`], [`az_user`] or [`ms_site`] classes. Calling the `new()` method for this class only constructs the R object; it does not call the Microsoft Graph API to retrieve or create the actual drive.
#'
#' @section File and folder operations:
#' This class exposes methods for carrying out common operations on files and folders. They call down to the corresponding methods for the [`ms_drive_item`] class. In this context, any paths to child items are relative to the root folder of the drive.
#' This class exposes methods for carrying out common operations on files and folders. They call down to the corresponding methods for the [`ms_drive_item`] class. In most cases an item can be specified either by path or ID. The former is more user-friendly but subject to change if the file is moved or renamed; the latter is an opaque string but is immutable regardless of file operations.
#'
#' `get_item(path, itemid)` retrieves a file or folder, as an object of class [`ms_drive_item`]. Specify either the path or ID, not both.
#'
#' `open_item` opens the given file or folder in your browser. If the file has an unrecognised type, most browsers will attempt to download it.
#'
#' `delete_item` deletes a file or folder. By default, it will ask for confirmation first.
#'
#' `create_share_link(path, itemid, type, expiry, password, scope)` returns a shareable link to the item.
#'
#' `get_item_properties` is a convenience function that returns the properties of a file or folder as a list.
#'
#' `set_item_properties` sets the properties of a file or folder. The new properties should be specified as individual named arguments to the method. Any existing properties that aren't listed as arguments will retain their previous values or be recalculated based on changes to other properties, as appropriate. You can also call the `update` method on the corresponding `ms_drive_item` object.
#'
#' `list_items(path, info, full_names, pagesize)` lists the items under the specified path.
#'
#' `list_files` is a synonym for `list_items`.
Expand All @@ -51,16 +61,6 @@
#'
#' `create_folder` creates a folder with the specified path. Trying to create an already existing folder is an error.
#'
#' `create_share_link(path, type, expiry, password, scope)` returns a shareable link to the item.
#'
#' `delete_item` deletes a file or folder. By default, it will ask for confirmation first.
#'
#' `get_item` retrieves the file or folder with the given path, as an object of class [`ms_drive_item`].
#'
#' `get_item_properties` is a convenience function that returns the properties of a file or folder as a list.
#'
#' `set_item_properties` sets the properties of a file or folder. The new properties should be specified as individual named arguments to the method. Any existing properties that aren't listed as arguments will retain their previous values or be recalculated based on changes to other properties, as appropriate. You can also call the `update` method on the corresponding `ms_drive_item` object.
#'
#' @section Shared items:
#' The `list_shared_items` method shows the files and folders that have been shared with you. This is a named list of drive items, that you can use to access the shared files/folders. The arguments are:
#' - `allow_external`: Whether to include items that were shared from outside tenants. The default is FALSE.
Expand Down Expand Up @@ -108,9 +108,15 @@
#' # file metadata (name, date created, etc)
#' drv$get_item_properties("myfile")
#'
#' # rename a file
#' # rename a file -- item ID remains the same, while name is changed
#' obj <- drv$get_item("myfile")
#' drv$set_item_properties("myfile", name="newname")
#'
#' # retrieve the renamed object by ID
#' id <- obj$properties$id
#' obj2 <- drv$get_item(itemid=id)
#' obj$properties$id == obj2$properties$id # TRUE
#'
#' # accessing shared files
#' shared_df <- drv$list_shared_items()
#' shared_df$remoteItem[[1]]$open()
Expand Down Expand Up @@ -151,35 +157,41 @@ public=list(
private$get_root()$create_folder(path)
},

download_file=function(src, dest=basename(src), overwrite=FALSE)
download_file=function(src=NULL, srcid=NULL, dest=basename(src), overwrite=FALSE)
{
self$get_item(src)$download(dest, overwrite=overwrite)
self$get_item(src, srcid)$download(dest, overwrite=overwrite)
},

download_folder=function(src, dest=basename(src), overwrite=FALSE, recursive=FALSE, parallel=FALSE)
download_folder=function(src=NULL, srcid=NULL, dest=basename(src), overwrite=FALSE, recursive=FALSE,
parallel=FALSE)
{
self$get_item(src)$download(dest, overwrite=overwrite, recursive=recursive, parallel=parallel)
self$get_item(src, srcid)$
download(dest, overwrite=overwrite, recursive=recursive, parallel=parallel)
},

create_share_link=function(path, type=c("view", "edit", "embed"), expiry="7 days", password=NULL, scope=NULL)
create_share_link=function(path=NULL, itemid=NULL, type=c("view", "edit", "embed"), expiry="7 days",
password=NULL, scope=NULL)
{
type <- match.arg(type)
self$get_item(path)$get_share_link(type, expiry, password, scope)
self$get_item(path, itemid)$get_share_link(type, expiry, password, scope)
},

open_item=function(path)
open_item=function(path=NULL, itemid=NULL)
{
self$get_item(path)$open()
self$get_item(path, itemid)$open()
},

delete_item=function(path, confirm=TRUE, by_item=FALSE)
delete_item=function(path=NULL, itemid=NULL, confirm=TRUE, by_item=FALSE)
{
self$get_item(path)$delete(confirm=confirm, by_item=by_item)
self$get_item(path, itemid)$delete(confirm=confirm, by_item=by_item)
},

get_item=function(path)
get_item=function(path=NULL, itemid=NULL)
{
op <- if(path != "/")
assert_one_arg(path, itemid, msg="Must supply one of item path or ID")
op <- if(!is.null(itemid))
file.path("items", itemid)
else if(path != "/")
{
path <- curl::curl_escape(gsub("^/|/$", "", path)) # remove any leading and trailing slashes
file.path("root:", path)
Expand All @@ -188,14 +200,14 @@ public=list(
ms_drive_item$new(self$token, self$tenant, self$do_operation(op))
},

get_item_properties=function(path)
get_item_properties=function(path=NULL, itemid=NULL)
{
self$get_item(path)$properties
self$get_item(path, itemid)$properties
},

set_item_properties=function(path, ...)
set_item_properties=function(path=NULL, itemid=NULL, ...)
{
self$get_item(path)$update(...)
self$get_item(path, itemid)$update(...)
},

list_shared_items=function(allow_external=TRUE, filter=NULL, n=Inf, pagesize=1000, info=NULL)
Expand Down
44 changes: 25 additions & 19 deletions man/ms_drive.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 16 additions & 2 deletions tests/testthat/test01_onedrive.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ test_that("OneDrive personal works",
src <- "../resources/file.json"
dest <- file.path(newfolder, basename(src))
newsrc <- tempfile()
expect_silent(od$upload_file(src, dest))
expect_silent(od$download_file(dest, newsrc))
expect_silent(od$upload_file(src, dest=dest))
expect_silent(od$download_file(dest, dest=newsrc))

expect_true(files_identical(src, newsrc))

Expand Down Expand Up @@ -177,6 +177,20 @@ test_that("Nested folder creation/deletion works",
})


test_that("Get item by ID works",
{
dir1 <- make_name(10)
src <- "../resources/file.json"

obj <- od$upload_file(src, file.path(dir1, "file.json"))
id <- obj$properties$id
obj2 <- od$get_item(itemid=id)
expect_identical(obj$properties$id, obj2$properties$id)

expect_silent(obj2$delete(confirm=FALSE))
})


test_that("Folder upload/download works",
{
srcdir <- tempfile()
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test02_business_onedrive.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test_that("OneDrive for Business works",
dest <- file.path(newfolder, basename(src))
newsrc <- tempfile()
expect_silent(od$upload_file(src, dest))
expect_silent(od$download_file(dest, newsrc))
expect_silent(od$download_file(dest, dest=newsrc))

expect_true(files_identical(src, newsrc))

Expand Down
Loading