diff --git a/DESCRIPTION b/DESCRIPTION index 13c71d5..9d9b958 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -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", , "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 diff --git a/NAMESPACE b/NAMESPACE index 6c48147..1ba6a82 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -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) diff --git a/NEWS.md b/NEWS.md index 5aab98b..1bdb4f9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/R/Microsoft365R.R b/R/Microsoft365R.R index 002520e..d3512ec 100644 --- a/R/Microsoft365R.R +++ b/R/Microsoft365R.R @@ -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 + diff --git a/R/build_chatmessage_body.R b/R/build_chatmessage_body.R index 17d4dcb..ebe551c 100644 --- a/R/build_chatmessage_body.R +++ b/R/build_chatmessage_body.R @@ -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)) @@ -99,7 +99,7 @@ make_mention.az_user <- function(object, i) ) } - +#' @noRd make_mention.ms_team <- function(object, i) { list( @@ -115,7 +115,7 @@ make_mention.ms_team <- function(object, i) ) } - +#' @noRd make_mention.ms_channel <- function(object, i) { list( @@ -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) diff --git a/R/build_email_request.R b/R/build_email_request.R index f9012bd..4d173b6 100644 --- a/R/build_email_request.R +++ b/R/build_email_request.R @@ -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, ...) { @@ -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, ...) { @@ -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() diff --git a/R/make_email_attachments.R b/R/make_email_attachments.R index 17baa46..220fd87 100644 --- a/R/make_email_attachments.R +++ b/R/make_email_attachments.R @@ -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) @@ -28,7 +29,7 @@ add_external_attachments.blastula_message <- function(object, email) } } - +#' @noRd add_external_attachments.envelope <- function(object, email) { require_emayili_0.6() @@ -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) diff --git a/R/ms_drive.R b/R/ms_drive.R index 41409c0..c05ed12 100644 --- a/R/ms_drive.R +++ b/R/ms_drive.R @@ -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: @@ -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( @@ -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) diff --git a/R/ms_drive_item.R b/R/ms_drive_item.R index 518e958..625ba0d 100644 --- a/R/ms_drive_item.R +++ b/R/ms_drive_item.R @@ -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. @@ -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( @@ -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) @@ -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 == "/") @@ -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 diff --git a/R/ms_list.R b/R/ms_list.R index 54b261d..2392dfa 100644 --- a/R/ms_list.R +++ b/R/ms_list.R @@ -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. @@ -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("\n", sep="") diff --git a/R/ms_list_item.R b/R/ms_list_item.R index c75a791..ec6d90c 100644 --- a/R/ms_list_item.R +++ b/R/ms_list_item.R @@ -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. @@ -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("\n", sep="") diff --git a/R/ms_outlook_email.R b/R/ms_outlook_email.R index 2006bca..52f288a 100644 --- a/R/ms_outlook_email.R +++ b/R/ms_outlook_email.R @@ -527,24 +527,26 @@ format_email_date <- function(datestr) } +#' @noRd make_reply_comment <- function(comment) { UseMethod("make_reply_comment") } +#' @noRd make_reply_comment.default <- function(comment) { as.character(comment) } - +#' @noRd make_reply_comment.blastula_message <- function(comment) { comment$html_str } - +#' @noRd make_reply_comment.envelope <- function(comment) { parts <- comment$parts diff --git a/R/ms_site.R b/R/ms_site.R index c43e267..474f406 100644 --- a/R/ms_site.R +++ b/R/ms_site.R @@ -17,6 +17,7 @@ #' - `list_drives(filter=NULL, n=Inf)`: List the drives (shared document libraries) associated with this site. #' - `get_drive(drive_name, drive_id)`: Retrieve a shared document library for this site. If the name and ID are not specified, this returns the default document library. #' - `list_subsites(filter=NULL, n=Inf)`: List the subsites of this site. +#' - `get_pages(type = c("sitePage", "page"))`: Returns SharePoint pages for this site. #' - `get_lists(filter=NULL, n=Inf)`: Returns the lists that are part of this site. #' - `get_list(list_name, list_id)`: Returns a specific list, either by name or ID. #' - `get_group()`: Retrieve the Microsoft 365 group associated with the site, if it exists. A site that backs a private Teams channel will not have a group associated with it. @@ -44,6 +45,7 @@ #' } #' @format An R6 object of class `ms_site`, inheriting from `ms_object`. #' @export +#' @importFrom curl curl_escape ms_site <- R6::R6Class("ms_site", inherit=ms_object, public=list( @@ -109,6 +111,43 @@ public=list( az_group$new(self$token, self$tenant, res[[1]]) }, + get_analytics=function() + { + self$do_operation("analytics") + }, + + get_pages=function(type = c("sitePage", "page")) + { + type <- match.arg(type) + + op <- switch (type, + page = "pages", + sitePage = "pages/microsoft.graph.sitePage" + ) + + self$do_operation(op) + }, + + # https://learn.microsoft.com/en-us/graph/api/site-list-columns + # FIXME: Add support for OData parameters + list_columns=function() + { + self$do_operation("columns") + }, + + # https://learn.microsoft.com/en-us/graph/api/site-list-permissions?view=graph-rest-beta&tabs=http + # FIXME: Add support for OData parameters + list_permissions=function() + { + self$do_operation("permissions") + }, + + # https://learn.microsoft.com/en-us/graph/api/site-list-contenttypes?view=graph-rest-beta&tabs=http + list_content_types=function() + { + self$do_operation("contentTypes") + }, + print=function(...) { cat("\n", sep="") diff --git a/R/normalize_src.R b/R/normalize_src.R index ba0e12f..2d53403 100644 --- a/R/normalize_src.R +++ b/R/normalize_src.R @@ -1,9 +1,10 @@ +#' @noRd normalize_src <- function(src) { UseMethod("normalize_src") } - +#' @noRd normalize_src.character <- function(src) { con <- file(src, open="rb") @@ -11,7 +12,7 @@ normalize_src.character <- function(src) list(con=con, size=size) } - +#' @noRd normalize_src.textConnection <- function(src) { # convert to raw connection @@ -21,7 +22,7 @@ normalize_src.textConnection <- function(src) list(con=con, size=size) } - +#' @noRd normalize_src.rawConnection <- function(src) { # need to read the data to get object size (!) diff --git a/man/ms_drive.Rd b/man/ms_drive.Rd index 3c94911..7d8d0b1 100644 --- a/man/ms_drive.Rd +++ b/man/ms_drive.Rd @@ -82,6 +82,8 @@ For copying and moving, the destination folder must exist beforehand. When copyi \code{list_files} is a synonym for \code{list_items}. +\code{list_activities} returns a list of activities for a drive. + \code{download_file} and \code{upload_file} transfer files between the local machine and the drive. For \code{download_file}, the default destination folder is the current (working) directory of your R session. For \code{upload_file}, there is no default destination folder; make sure you specify the destination explicitly. \code{download_folder} and \code{upload_folder} transfer all the files in a folder. If \code{recursive} is TRUE, all subfolders will also be transferred recursively. The \code{parallel} argument can have the following values: diff --git a/man/ms_drive_item.Rd b/man/ms_drive_item.Rd index 18764db..6eb0b79 100644 --- a/man/ms_drive_item.Rd +++ b/man/ms_drive_item.Rd @@ -60,17 +60,23 @@ This class exposes methods for carrying out common operations on files and folde \code{open} opens this file or folder in your browser. If the file has an unrecognised type, most browsers will attempt to download it. -\code{list_items(path, info, full_names, filter, n, pagesize)} lists the items under the specified path. It is the analogue of base R's \code{dir}/\code{list.files}. Its arguments are +\code{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 \code{dir}/\code{list.files}. Its arguments are \itemize{ \item \code{path}: The path. -\item \code{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 \emph{all} the properties for each item (this can be large). +\item \code{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 \code{select} is ignored). If "all", a data frame is returned containing \emph{all} the properties for each item (this can be large). Supply \code{select} (if info is "partial" pr "all") to specify which columns to include in the returned data frame. \item \code{full_names}: Whether to prefix the folder path to the names of the items. -\item \verb{filter, n}: See 'List methods' below. +\item \verb{filter, select, n}: See 'List methods' below. \item \code{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. } \code{list_files} is a synonym for \code{list_items}. +\code{list_permissions} returns a list of permissions for a drive item. + +\code{list_versions} returns a list of drive item versions. + +\code{list_activities} returns a list of activities for a drive item. + \code{download} downloads the item to the local machine. If this is a file, it is downloaded; in this case, the \code{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 \code{recursive} argument is TRUE. \code{upload} uploads a file or folder from the local machine into the folder item. The \code{src} argument can be the path to the source file, a \link{rawConnection} or a \link{textConnection} object. If \code{src} is a folder, all its files are uploaded, including subfolders if the \code{recursive} argument iS TRUE. An \code{ms_drive_item} object is returned invisibly. diff --git a/man/ms_list.Rd b/man/ms_list.Rd index 6e2470a..b7356d6 100644 --- a/man/ms_list.Rd +++ b/man/ms_list.Rd @@ -29,7 +29,8 @@ Class representing a list in a SharePoint site. \item \code{do_operation(...)}: Carry out an arbitrary operation on the list. \item \code{sync_fields()}: Synchronise the R object with the list metadata in Microsoft Graph. \item \code{list_items(filter, select, all_metadata, as_data_frame, pagesize)}: Queries the list and returns items as a data frame. See 'List querying' below. -\item \code{get_column_info()}: Return a data frame containing metadata on the columns (fields) in the list. +\item \code{get_column_info(simplify=TRUE)}: Return a list or data frame containing metadata on the columns (fields) in the list. +\item \code{create_column(definition)}: Create a new column in the list. \item \code{get_item(id)}: Get an individual list item. \item \code{create_item(...)}: Create a new list item, using the named arguments as fields. \item \code{update_item(id, ...)}: Update the \emph{data} fields in the given item, using the named arguments. To update the item's metadata, use \code{get_item()} to retrieve the item object, then call its \code{update()} method. diff --git a/man/ms_list_item.Rd b/man/ms_list_item.Rd index 1de1ffb..313984c 100644 --- a/man/ms_list_item.Rd +++ b/man/ms_list_item.Rd @@ -28,6 +28,7 @@ Class representing an item in a SharePoint list. \item \code{update(...)}: Update the item's properties (metadata) in Microsoft Graph. To update the list \emph{data}, update the \code{fields} property. See the examples below. \item \code{do_operation(...)}: Carry out an arbitrary operation on the item. \item \code{sync_fields()}: Synchronise the R object with the item data and metadata in Microsoft Graph. +\item \code{create_link()}: Create a shared link to a list item. } } diff --git a/man/ms_site.Rd b/man/ms_site.Rd index 03ed4ac..3259eae 100644 --- a/man/ms_site.Rd +++ b/man/ms_site.Rd @@ -31,6 +31,7 @@ Class representing a SharePoint site. \item \code{list_drives(filter=NULL, n=Inf)}: List the drives (shared document libraries) associated with this site. \item \code{get_drive(drive_name, drive_id)}: Retrieve a shared document library for this site. If the name and ID are not specified, this returns the default document library. \item \code{list_subsites(filter=NULL, n=Inf)}: List the subsites of this site. +\item \code{get_pages(type = c("sitePage", "page"))}: Returns SharePoint pages for this site. \item \code{get_lists(filter=NULL, n=Inf)}: Returns the lists that are part of this site. \item \code{get_list(list_name, list_id)}: Returns a specific list, either by name or ID. \item \code{get_group()}: Retrieve the Microsoft 365 group associated with the site, if it exists. A site that backs a private Teams channel will not have a group associated with it.