diff --git a/.github/workflows/check-standard.yaml b/.github/workflows/check-standard.yaml index 7004cd3..6f50735 100644 --- a/.github/workflows/check-standard.yaml +++ b/.github/workflows/check-standard.yaml @@ -24,7 +24,7 @@ jobs: RSPM: ${{ matrix.config.rspm }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 # required for mirroring, see https://stackoverflow.com/a/64272409/474349 @@ -39,11 +39,11 @@ jobs: xargs -L1 git config --unset-all git push --prune https://token:$token@github.com/${CLOUDYR_REPO}.git +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/* - - uses: r-lib/actions/setup-r@master + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} - - uses: r-lib/actions/setup-pandoc@master + - uses: r-lib/actions/setup-pandoc@v2 - name: Query dependencies run: | @@ -54,7 +54,7 @@ jobs: - name: Cache R packages if: runner.os != 'Windows' - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ env.R_LIBS_USER }} key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} @@ -85,7 +85,7 @@ jobs: - name: Upload check results if: failure() - uses: actions/upload-artifact@main + uses: actions/upload-artifact@v3 with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check diff --git a/DESCRIPTION b/DESCRIPTION index f30c16d..369ae91 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: Microsoft365R Title: Interface to the 'Microsoft 365' Suite of Cloud Services -Version: 2.3.4 +Version: 2.3.4.9000 Authors@R: c( person("Hong", "Ooi", , "hongooi73@gmail.com", role = c("aut", "cre")), person("Roman", "Zenka", role="ctb"), diff --git a/NEWS.md b/NEWS.md index 92f4355..c7ddebd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# Microsoft365R 2.3.4.9000 + +- Fix broken functionality for shared items in OneDrive/Sharepoint. In particular, this should allow using the MS365 backend with the pins package (#149/#129). + # Microsoft365R 2.3.4 - Fix a bug in retrieving a drive by name (#104). diff --git a/R/Microsoft365R.R b/R/Microsoft365R.R index e14cf0a..8274a4c 100644 --- a/R/Microsoft365R.R +++ b/R/Microsoft365R.R @@ -8,6 +8,9 @@ utils::globalVariables(c("self", "private")) # set Graph API to beta, for more powerful permissions options(azure_graph_api_version="beta") + # whether to use item IDs in OD/SPO paths: values are TRUE, FALSE, "remote" + options(microsoft365r_use_itemid_in_path="remote") + register_graph_class("site", ms_site, function(props) grepl("sharepoint", props$id, fixed=TRUE)) diff --git a/R/build_email_request.R b/R/build_email_request.R index 3ad44e9..f9012bd 100644 --- a/R/build_email_request.R +++ b/R/build_email_request.R @@ -81,7 +81,7 @@ build_email_recipients <- function(to, cc, bcc, reply_to) make_recipients <- function(addr_list) { # NA means don't update current value - if(!is_empty(addr_list) && is.na(addr_list)) + if(!is_empty(addr_list) && any(is.na(addr_list))) return(NA) # handle case of a single az_user object @@ -113,7 +113,7 @@ build_email_recipients <- function(to, cc, bcc, reply_to) bccRecipients=make_recipients(bcc), replyTo=make_recipients(reply_to) ) - out[sapply(out, function(x) is_empty(x) || !is.na(x))] + out[sapply(out, function(x) is_empty(x) || all(!is.na(x)))] } diff --git a/R/ms_drive.R b/R/ms_drive.R index 2ef7403..7f56fd9 100644 --- a/R/ms_drive.R +++ b/R/ms_drive.R @@ -181,7 +181,7 @@ public=list( self$get_item(path)$update(...) }, - list_shared_items=function(info=c("partial", "items", "all"), allow_external=FALSE, + list_shared_items=function(info=c("partial", "items", "all"), allow_external=TRUE, filter=NULL, n=Inf, pagesize=1000) { info <- match.arg(info) @@ -204,6 +204,8 @@ public=list( df$isdir <- if(!is.null(df$folder)) !is.na(df$folder$childCount) else rep(FALSE, nrow(df)) + if(is.null(df$size)) + df$size <- rep(NA, nrow(df)) } df$remoteItem <- lapply(seq_len(nrow(df)), diff --git a/R/ms_drive_item.R b/R/ms_drive_item.R index f1d6f95..a9e9105 100644 --- a/R/ms_drive_item.R +++ b/R/ms_drive_item.R @@ -198,7 +198,13 @@ public=list( if(!is.null(filter)) opts$`filter` <- filter - op <- sub("root:/children", "root/children", paste0(private$make_absolute_path(path), ":/children")) + fullpath <- private$make_absolute_path(path) + # possible fullpath formats -> string to append: + # drives/xxx/root -> /children + # drives/xxx/root:/foo/bar -> :/children + # drives/xxx/items/yyy -> /children + # drives/xxx/items/yyy:/foo/bar -> :/children + op <- if(grepl(":/", fullpath)) paste0(fullpath, ":/children") else paste0(fullpath, "/children") children <- call_graph_endpoint(self$token, op, options=opts, simplify=TRUE) # get file list as a data frame, or return the iterator immediately if n is NULL @@ -261,7 +267,15 @@ public=list( con <- file(src, open="rb") on.exit(close(con)) - op <- paste0(private$make_absolute_path(dest), ":/createUploadSession") + fullpath <- private$make_absolute_path(dest) + # possible fullpath formats -> string to append: + # drives/xxx/root -> /createUploadSession + # drives/xxx/root:/foo/bar -> :/createUploadSession + # drives/xxx/items/yyy -> /createUploadSession + # drives/xxx/items/yyy:/foo/bar -> :/createUploadSession + op <- if(grepl(":/", fullpath)) + paste0(fullpath, ":/createUploadSession") + else paste0(fullpath, "/createUploadSession") upload_dest <- call_graph_endpoint(self$token, op, http_verb="POST")$uploadUrl size <- file.size(src) @@ -334,15 +348,21 @@ private=list( # dest = . or '' --> this item # dest = .. --> parent folder # dest = (childname) --> path to named child - make_absolute_path=function(dest=".") + make_absolute_path=function(dest=".", use_itemid=getOption("microsoft365r_use_itemid_in_path")) + { + if(use_itemid == "remote") + use_itemid <- private$remote + + if(use_itemid) + private$make_absolute_path_with_itemid(dest) + else private$make_absolute_path_from_root(dest) + }, + + make_absolute_path_from_root=function(dest=".") { if(dest == ".") dest <- "" - # this is needed to find the correct parent folder for a shared item - if(private$remote) - self$sync_fields() - parent <- self$properties$parentReference name <- self$properties$name op <- if(name == "root") @@ -361,6 +381,25 @@ private=list( utils::URLencode(enc2utf8(sub(":?/?$", "", op))) }, + # construct path using this item's ID + # ".." not supported + make_absolute_path_with_itemid=function(dest=".") + { + driveid <- self$properties$parentReference$driveId + id <- self$properties$id + base <- sprintf("drives/%s/items/%s", driveid, id) + + if(dest == "." || dest == "") + return(base) + else if(dest == "..") + stop("Path with item ID to parent folder not supported", call.=FALSE) + else if(substr(dest, 1, 1) == "/") + stop("Absolute path incompatible with path starting from item ID", call.=FALSE) + + op <- sprintf("%s:/%s", base, dest) + utils::URLencode(enc2utf8(op)) + }, + assert_is_folder=function() { if(!self$is_folder())