Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6d94bc2
Add list_activities, list_versions, and list_permissions methods
elipousson Jun 13, 2024
d7ebca0
Add create_link method to ms_list_item
elipousson Jun 13, 2024
4b99446
Add get_analytics, list_columns, list_permission, and list_content_types
elipousson Jun 13, 2024
d01dc52
Add create_column method
elipousson Jun 18, 2024
28547f4
Update docs for ms_list_item
elipousson Jun 18, 2024
801b99f
Tidy DESCRIPTION
elipousson Jun 18, 2024
bb93f00
Update ms_list docs
elipousson Jun 18, 2024
217fe64
Add missing imports
elipousson Aug 20, 2024
0953a06
Export methods to avoid warning w/ document
elipousson Aug 20, 2024
10fa4a4
Add get_pages method to ms_site
elipousson Aug 20, 2024
697ae77
Don't export methods just use noRd
elipousson Aug 20, 2024
d6f3259
use noRd not exportS3Method
elipousson Aug 20, 2024
1c85216
Update NAMESPACE
elipousson Aug 20, 2024
7a9bbda
Update ms_list docs
elipousson Aug 20, 2024
97bc86b
Add Eli Pousson as contributor
elipousson Aug 20, 2024
d9cb702
Update NEWS w/ additional methods
elipousson Aug 20, 2024
cc9b205
Add select argument to list_items method
elipousson Oct 25, 2024
1d9d130
Update NEWS w/ info re: list_items method change
elipousson Oct 25, 2024
c143019
linting
hongooi73 Feb 24, 2025
824469f
Merge branch 'master' into pr/214
hongooi73 Feb 24, 2025
c06a271
Merge branch 'master' into pages-lists-features
elipousson May 1, 2025
b3b064b
Expose `expand` argument in `get_item`
elipousson May 2, 2025
7f75e91
Modify `create_column` method to use `...` arg
elipousson May 2, 2025
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
52 changes: 32 additions & 20 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,50 @@ Title: Interface to the 'Microsoft 365' Suite of Cloud Services
Version: 2.4.1
Authors@R: c(
person("Hong", "Ooi", , "hongooi73@gmail.com", role = c("aut", "cre")),
person("Roman", "Zenka", role="ctb"),
person("Robert", "Ashton", role="ctb"),
person("Philip", "Zheng", role="ctb"),
person("Microsoft", role="cph")
)
Description: An interface to the 'Microsoft 365' (formerly known as 'Office 365') suite of cloud services, building on the framework supplied by the 'AzureGraph' package. Enables access from R to data stored in 'Teams', 'SharePoint Online' and 'OneDrive', including the ability to list drive folder contents, upload and download files, send messages, and retrieve data lists. Also provides a full-featured 'Outlook' email client, with the ability to send emails and manage emails and mail folders.
URL: https://github.com/Azure/Microsoft365R https://github.com/Azure/AzureR
BugReports: https://github.com/Azure/Microsoft365R/issues
person("Roman", "Zenka", role = "ctb"),
person("Robert", "Ashton", role = "ctb"),
person("Philip", "Zheng", role = "ctb"),
person("Eli", "Pousson", , "eli.pousson@gmail.com", role = "ctb",
comment = c(ORCID = "0000-0001-8280-1706")),
person("Microsoft", role = "cph")
)
Description: An interface to the 'Microsoft 365' (formerly known as
'Office 365') suite of cloud services, building on the framework
supplied by the 'AzureGraph' package. Enables access from R to data
stored in 'Teams', 'SharePoint Online' and 'OneDrive', including the
ability to list drive folder contents, upload and download files, send
messages, and retrieve data lists. Also provides a full-featured
'Outlook' email client, with the ability to send emails and manage
emails and mail folders.
License: MIT + file LICENSE
VignetteBuilder: knitr
URL: https://github.com/Azure/Microsoft365R
https://github.com/Azure/AzureR
BugReports: https://github.com/Azure/Microsoft365R/issues
Depends:
R (>= 3.3)
Imports:
AzureAuth,
AzureGraph (>= 1.3.1),
utils,
parallel,
tools,
curl,
httr,
jsonlite,
mime,
parallel,
R6,
vctrs,
mime
tools,
utils,
vctrs
Suggests:
openssl,
knitr,
rmarkdown,
testthat,
blastula,
emayili,
knitr,
openssl,
readr,
readxl
readxl,
rmarkdown,
testthat
VignetteBuilder:
knitr
Encoding: UTF-8
Roxygen: list(markdown=TRUE, r6=FALSE)
RoxygenNote: 7.2.1
RoxygenNote: 7.3.2
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ export(ms_team_member)
export(personal_onedrive)
export(sharepoint_site)
import(AzureGraph)
importFrom(curl,curl_escape)
importFrom(parallel,makeCluster)
importFrom(parallel,parLapply)
importFrom(parallel,stopCluster)
importFrom(tools,file_ext)
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Microsoft365R development

- Expose `select` argument for `ms_drive$list_items()` method (ignored when `info="name"`).
- Expose `simplify` argument for `ms_list$get_column_info()` method.
- Add `ms_list$create_link()` method for creating a shared link to a list item.
- Add `ms_list$create_column()` method.
- Add `ms_site$get_pages()` method (#190)
- Add `ms_site$get_analytics()`, `ms_site$list_permissions()`, and `ms_site$list_content_types()` methods. (#209)
- Add `ms_drive$list_activities()` (#209)

# Microsoft365R 2.4.1

## OneDrive/SharePoint
Expand All @@ -17,6 +27,7 @@

## Other

- Add Eli Pousson to contributors.
- Remove references to the Microsoft365 CLI, as this no longer has a multi-tenant app registration and hence cannot be used for authentication. This means you'll have to either allow the Microsoft365R app ID within your tenant or create your own app registration (both of which will require Azure admin access). (#215)


Expand Down
4 changes: 4 additions & 0 deletions R/Microsoft365R.R
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ get_confirmation <- get("get_confirmation", getNamespace("AzureGraph"))
# to combine paged results into a single data frame: individual pages can have
# different structures, which will break base::rbind
vctrs::vec_rbind


#' @importFrom R6 R6Class

10 changes: 5 additions & 5 deletions R/build_chatmessage_body.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ build_chatmessage_body <- function(channel, body, content_type, attachments, inl
call_body
}


#' @noRd
make_mention <- function(object, i)
{
UseMethod("make_mention")
}


#' @noRd
make_mention.az_user <- function(object, i)
{
name <- if(!is.null(object$properties$displayName))
Expand All @@ -99,7 +99,7 @@ make_mention.az_user <- function(object, i)
)
}


#' @noRd
make_mention.ms_team <- function(object, i)
{
list(
Expand All @@ -115,7 +115,7 @@ make_mention.ms_team <- function(object, i)
)
}


#' @noRd
make_mention.ms_channel <- function(object, i)
{
list(
Expand All @@ -131,7 +131,7 @@ make_mention.ms_channel <- function(object, i)
)
}


#' @noRd
make_mention.ms_team_member <- function(object, i)
{
make_mention(object$get_aaduser(), i)
Expand Down
7 changes: 4 additions & 3 deletions R/build_email_request.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# methods for different email formats: default, blastula, emayili

#' @noRd
build_email_request <- function(body, ...)
{
UseMethod("build_email_request")
}


#' @noRd
build_email_request.character <- function(body, content_type,
subject=NULL, to=NA, cc=NA, bcc=NA, reply_to=NA, token=NULL, user_id=NULL, ...)
{
Expand All @@ -21,7 +22,7 @@ build_email_request.character <- function(body, content_type,
utils::modifyList(req, build_email_recipients(to, cc, bcc, reply_to))
}


#' @noRd
build_email_request.blastula_message <- function(body, content_type,
subject=NULL, to=NA, cc=NA, bcc=NA, reply_to=NA, token=NULL, user_id=NULL, ...)
{
Expand All @@ -37,7 +38,7 @@ build_email_request.blastula_message <- function(body, content_type,
utils::modifyList(req, build_email_recipients(to, cc, bcc, reply_to))
}


#' @noRd
build_email_request.envelope <- function(body, token=NULL, user_id=NULL, ...)
{
require_emayili_0.6()
Expand Down
7 changes: 4 additions & 3 deletions R/make_email_attachments.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#' @noRd
add_external_attachments <- function(object, email)
{
UseMethod("add_external_attachments")
}


#' @noRd
add_external_attachments.blastula_message <- function(object, email)
{
for(a in object$attachments)
Expand All @@ -28,7 +29,7 @@ add_external_attachments.blastula_message <- function(object, email)
}
}


#' @noRd
add_external_attachments.envelope <- function(object, email)
{
require_emayili_0.6()
Expand Down Expand Up @@ -60,7 +61,7 @@ add_external_attachments.envelope <- function(object, email)
}
}


#' @noRd
add_external_attachments.default <- function(object, email)
{
# do nothing if message object is not a recognised class (from blastula or emayili)
Expand Down
7 changes: 7 additions & 0 deletions R/ms_drive.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
#'
#' `list_files` is a synonym for `list_items`.
#'
#' `list_activities` returns a list of activities for a drive.
#'
#' `download_file` and `upload_file` transfer files between the local machine and the drive. For `download_file`, the default destination folder is the current (working) directory of your R session. For `upload_file`, there is no default destination folder; make sure you specify the destination explicitly.
#'
#' `download_folder` and `upload_folder` transfer all the files in a folder. If `recursive` is TRUE, all subfolders will also be transferred recursively. The `parallel` argument can have the following values:
Expand Down Expand Up @@ -158,6 +160,7 @@
#' }
#' @format An R6 object of class `ms_drive`, inheriting from `ms_object`.
#' @export
#' @importFrom curl curl_escape
ms_drive <- R6::R6Class("ms_drive", inherit=ms_object,

public=list(
Expand All @@ -174,6 +177,10 @@ public=list(
private$get_root()$list_items(path, ...)
},

list_activites=function() {
self$do_operation("activities")
},

upload_file=function(src, dest, blocksize=32768000)
{
private$get_root()$upload(src, dest, blocksize)
Expand Down
55 changes: 46 additions & 9 deletions R/ms_drive_item.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,21 @@
#'
#' `open` opens this file or folder in your browser. If the file has an unrecognised type, most browsers will attempt to download it.
#'
#' `list_items(path, info, full_names, filter, n, pagesize)` lists the items under the specified path. It is the analogue of base R's `dir`/`list.files`. Its arguments are
#' `list_items(path, info, full_names, filter, select, n, pagesize)` lists the items under the specified path. It is the analogue of base R's `dir`/`list.files`. Its arguments are
#' - `path`: The path.
#' - `info`: The information to return: either "partial", "name" or "all". If "partial", a data frame is returned containing the name, size, ID and whether the item is a file or folder. If "name", a vector of file/folder names is returned. If "all", a data frame is returned containing _all_ the properties for each item (this can be large).
#' - `info`: The information to return: either "partial", "name" or "all". If "partial", a data frame is returned containing the name, size, ID and whether the item is a file or folder. If "name", a vector of file/folder names is returned (and any value passed to `select` is ignored). If "all", a data frame is returned containing _all_ the properties for each item (this can be large). If `select` is supplied and `info` is "partial" or "all", only the specified columns are included in the returned data frame.
#' - `full_names`: Whether to prefix the folder path to the names of the items.
#' - `filter, n`: See 'List methods' below.
#' - `filter, select, n`: See 'List methods' below.
#' - `pagesize`: The number of results to return for each call to the REST endpoint. You can try reducing this argument below the default of 1000 if you are experiencing timeouts.
#'
#' `list_files` is a synonym for `list_items`.
#'
#' `list_permissions` returns a list of permissions for a drive item.
#'
#' `list_versions` returns a list of drive item versions.
#'
#' `list_activities` returns a list of activities for a drive item.
#'
#' `download` downloads the item to the local machine. If this is a file, it is downloaded; in this case, the `dest` argument can be the path to the destination file, or NULL to return the downloaded content in a raw vector. If the item is a folder, all its files are downloaded, including subfolders if the `recursive` argument is TRUE.
#'
#' `upload` uploads a file or folder from the local machine into the folder item. The `src` argument can be the path to the source file, a [rawConnection] or a [textConnection] object. If `src` is a folder, all its files are uploaded, including subfolders if the `recursive` argument iS TRUE. An `ms_drive_item` object is returned invisibly.
Expand All @@ -62,8 +68,9 @@
#' - A cluster object, created via the parallel package
#' - FALSE: The transfer is done serially
#'
#' `get_item` retrieves the file or folder with the given path, as another object of class `ms_drive_item`.
#'
#' `get_item(expand)` retrieves the file or folder with the given path, as another object of class `ms_drive_item`.
#' - `expand`: If `expand="fields"` include custom column values associated with the item.

#' - `copy` and `move` can take the destination location as either a full pathname (in the `dest` argument), or a name plus a drive item object (in the `dest_folder_item` argument). If the latter is supplied, any path in `dest` is ignored with a warning. Note that copying is an _asynchronous_ operation, meaning the method returns before the copy is complete.
#'
#' For copying and moving, the destination folder must exist beforehand. When copying/moving a large number of files, it's much more efficient to supply the destination folder in the `dest_folder_item` argument rather than as a path.
Expand Down Expand Up @@ -152,6 +159,8 @@
#' }
#' @format An R6 object of class `ms_drive_item`, inheriting from `ms_object`.
#' @export
#' @importFrom parallel makeCluster stopCluster parLapply
#' @importFrom tools file_ext
ms_drive_item <- R6::R6Class("ms_drive_item", inherit=ms_object,

public=list(
Expand Down Expand Up @@ -211,6 +220,21 @@ public=list(
httr::BROWSE(self$properties$webUrl)
},

# https://learn.microsoft.com/en-us/graph/api/driveitem-list-permissions
list_permissions=function() {
self$do_operation("permissions")
},

# https://learn.microsoft.com/en-us/graph/api/driveitem-list-versions
list_versions=function() {
self$do_operation("versions")
},

# https://learn.microsoft.com/en-us/graph/api/activities-list
list_activities=function() {
self$do_operation("activities")
},

create_share_link=function(type=c("view", "edit", "embed"), expiry="7 days", password=NULL, scope=NULL)
{
type <- match.arg(type)
Expand All @@ -233,7 +257,7 @@ public=list(
else res$link$webUrl
},

list_items=function(path="", info=c("partial", "name", "all"), full_names=FALSE, filter=NULL, n=Inf, pagesize=1000)
list_items=function(path="", info=c("partial", "name", "all"), full_names=FALSE, filter=NULL, select=NULL, n=Inf, pagesize=1000)
{
private$assert_is_folder()
if(path == "/")
Expand All @@ -244,6 +268,10 @@ public=list(
name=list(`$select`="name", `$top`=pagesize),
list(`$top`=pagesize)
)

if (!is.null(select) && info != "name")
opts$`$select` <- paste0(select, collapse = ",")

if(!is.null(filter))
opts$`filter` <- filter

Expand Down Expand Up @@ -272,6 +300,11 @@ public=list(

if(full_names)
df$name <- file.path(sub("^/", "", path), df$name)

if (!is.null(select)) {
return(df)
}

switch(info,
partial=df[c("name", "size", "isdir", "id")],
name=df$name,
Expand All @@ -283,10 +316,10 @@ public=list(
)
},

get_item=function(path)
get_item=function(path, expand = NULL)
{
private$assert_is_folder()
op <- private$make_absolute_path(path)
op <- private$make_absolute_path(path, expand = expand)
ms_drive_item$new(self$token, self$tenant, call_graph_endpoint(self$token, op))
},

Expand Down Expand Up @@ -657,7 +690,7 @@ private=list(
# dest = . or '' --> this item
# dest = .. --> parent folder
# dest = (childname) --> path to named child
make_absolute_path=function(dest=".", use_itemid=getOption("microsoft365r_use_itemid_in_path"))
make_absolute_path=function(dest=".", use_itemid=getOption("microsoft365r_use_itemid_in_path"), expand=NULL)
{
if(use_itemid == "remote")
use_itemid <- !is.null(private$remoteItem)
Expand Down Expand Up @@ -692,6 +725,10 @@ private=list(
}
if(dest != "..")
op <- file.path(op, dest)

if (!is.null(expand))
op <- sprintf("%s?$expand=%s", op, expand)

utils::URLencode(enc2utf8(sub(":?/?$", "", op)))
},

Expand Down
Loading