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

Add support for versions/activities (#209) and partial support for SharePoint pages (#190) #214

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
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
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.0.9000
Authors@R: c(
person("Hong", "Ooi", , "[email protected]", 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", , "[email protected]", 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
Expand Up @@ -5,11 +5,22 @@
- In the `ms_drive_item$load_dataframe()` method, pass the `...` argument to `read_delim`.
- Add the ability to load Excel files (with extension .xls or .xlsx) to the `ms_drive_item$load_dataframe()` method. This requires the readxl package to be installed.
- Fix a bug in downloading shared files in business SharePoint/OneDrive (#189)
- 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)

## Planner

- Fix a bug in the `ms_plan$get_details()` method.

## Other

- Add Eli Pousson to contributors.

# Microsoft365R 2.4.0

## OneDrive/SharePoint
Expand Down
4 changes: 4 additions & 0 deletions R/Microsoft365R.R
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,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
35 changes: 31 additions & 4 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). Supply `select` (if info is "partial" pr "all") to specify which columns to include 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 Down Expand Up @@ -152,6 +158,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 +219,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 +256,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 +267,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
14 changes: 11 additions & 3 deletions R/ms_list.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#' - `do_operation(...)`: Carry out an arbitrary operation on the list.
#' - `sync_fields()`: Synchronise the R object with the list metadata in Microsoft Graph.
#' - `list_items(filter, select, all_metadata, as_data_frame, pagesize)`: Queries the list and returns items as a data frame. See 'List querying' below.
#' - `get_column_info()`: Return a data frame containing metadata on the columns (fields) in the list.
#' - `get_column_info(simplify=TRUE)`: Return a list or data frame containing metadata on the columns (fields) in the list.
#' - `create_column(definition)`: Create a new column in the list.
#' - `get_item(id)`: Get an individual list item.
#' - `create_item(...)`: Create a new list item, using the named arguments as fields.
#' - `update_item(id, ...)`: Update the _data_ fields in the given item, using the named arguments. To update the item's metadata, use `get_item()` to retrieve the item object, then call its `update()` method.
Expand Down Expand Up @@ -134,12 +135,19 @@ public=list(
invisible(lapply(seq_len(nrow(data)), function(i) do.call(self$create_item, data[i, , drop=FALSE])))
},

get_column_info=function()
get_column_info=function(simplify=TRUE)
{
res <- self$do_operation(options=list(expand="columns"), simplify=TRUE)
res <- self$do_operation(options=list(expand="columns"), simplify=simplify)
res$columns
},

create_column=function(definition)
{
stopifnot(is.list(definition))
res <- self$do_operation(options=list(expand="columns"), encode="json", body=definition, http_verb="POST")
res
},

print=function(...)
{
cat("<Sharepoint list '", self$properties$displayName, "'>\n", sep="")
Expand Down
10 changes: 10 additions & 0 deletions R/ms_list_item.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#' - `update(...)`: Update the item's properties (metadata) in Microsoft Graph. To update the list _data_, update the `fields` property. See the examples below.
#' - `do_operation(...)`: Carry out an arbitrary operation on the item.
#' - `sync_fields()`: Synchronise the R object with the item data and metadata in Microsoft Graph.
#' - `create_link()`: Create a shared link to a list item.
#'
#' @section Initialization:
#' Creating new objects of this class should be done via the `get_item` method of the [`ms_list`] class. 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 item.
Expand Down Expand Up @@ -62,6 +63,15 @@ public=list(
super$initialize(token, tenant, properties)
},

# https://learn.microsoft.com/en-us/graph/api/listitem-createlink
create_link = function() {
self$do_operation("createLink", http_verb = "POST")
},

# delete = function() {
# self$do_operation(http_verb = "DELETE")
# },

print=function(...)
{
cat("<Sharepoint list item '", self$properties$fields$Title, "'>\n", sep="")
Expand Down
Loading