#' Get group information from the Posit Connect server
#'
#' @param src The source object.
#' @param page_size The number of records to return per page (max 500).
#' @param prefix Filters groups by prefix (group name).
#' The filter is case insensitive.
#' @param limit The number of groups to retrieve before paging stops. Default
#' is to return all results; however, for Connect server versions older than
#' 2025.04.0, `limit` is capped at 500 when `prefix` is provided.
#'
#' @return
#' A tibble with the following columns:
#'
#' * `guid`: The unique identifier of the group
#' * `name`: The group name
#' * `owner_guid`: The group owner's unique identifier. When using LDAP or
#' Proxied authentication with group provisioning enabled this property
#' will always be null.
#'
#' @details
#' Please see https://docs.posit.co/connect/api/#get-/v1/groups for more information.
#'
#' @examples
#' \dontrun{
#' library(connectapi)
#' client <- connect()
#'
#' # get all groups
#' get_groups(client, limit = Inf)
#' }
#'
#' @family groups functions
#' @export
get_groups <- function(src, page_size = 500, prefix = NULL, limit = Inf) {
validate_R6_class(src, "Connect")
# Prior to 2025.04.0, the `v1/groups` endpoint ignored page_number when
# `prefix` was provided, always returning the first page.
# So for those versions, we should request the max page size needed to
# satisfy `limit`, and make them equal, so that page_offset() only fetches
# one page.
# Proper pagination added in https://github.com/posit-dev/connect/pull/31086
if (
!is.null(prefix) && compare_connect_version(src$version, "2025.04.0") < 0
) {
# The max page size allowed by the server is 500, so in this version of
# Connect, that's the maximum number of groups we can get.
page_size <- limit <- min(500, limit)
}
res <- page_offset(
src,
src$groups(page_size = page_size, prefix = prefix),
limit = limit
)
parse_connectapi_typed(res, connectapi_ptypes$groups)
}
#' Get users within a specific group
#'
#' @param src A Connect client object
#' @param guid A group GUID identifier
#'
#' @return
#' A tibble with the following columns:
#'
#' * `email`: The user's email
#' * `username`: The user's username
#' * `first_name`: The user's first name
#' * `last_name`: The user's last name
#' * `user_role`: The user's role. It may have a value of administrator,
#' publisher or viewer.
#' * `created_time`: The timestamp (in RFC3339 format) when the user
#' was created in the Posit Connect server
#' * `updated_time`: The timestamp (in RFC3339 format) when the user
#' was last updated in the Posit Connect server
#' * `active_time`: The timestamp (in RFC3339 format) when the user
#' was last active on the Posit Connect server
#' * `confirmed`: When false, the created user must confirm their
#' account through an email. This feature is unique to password
#' authentication.
#' * `locked`: Whether or not the user is locked
#' * `guid`: The user's GUID, or unique identifier, in UUID RFC4122 format
#'
#' @details
#' Please see https://docs.posit.co/connect/api/#get-/v1/groups/-group_guid-/members
#' for more information.
#'
#' @examples
#' \dontrun{
#' library(connectapi)
#' client <- connect()
#'
#' # get the first 20 groups
#' groups <- get_groups(client)
#'
#' group_guid <- groups$guid[1]
#'
#' get_group_members(client, guid = group_guid)
#' }
#'
#' @family groups functions
#' @export
get_group_members <- function(src, guid) {
validate_R6_class(src, "Connect")
res <- src$group_members(guid)
parse_connectapi(res$results)
}
#' Get content access permissions for a group or groups
#'
#' @param src A Connect client object
#' @param guids A character vector of group guids
#'
#' @return
#' A tibble with the following columns:
#' * `group_guid`: The group's GUID
#' * `group_name`: The group's name
#' * `content_guid`: The content item's GUID
#' * `content_name`: The content item's name
#' * `content_title`: The content item's title
#' * `access_type`: The access type of the content item ("all", "logged_in", or "acl")
#' * `role`: The access type that members of the group have to the
#' content item, "publisher" or "viewer".
#'
#' @examples
#' \dontrun{
#' library(connectapi)
#' client <- connect()
#'
#' # Get a data frame of groups
#' groups <- get_groups(client)
#'
#' # Get permissions for a single group by passing in the corresponding row.
#' get_group_content(client, groups[1, "guid"])
#' dplyr::filter(groups, name = "research_scientists") %>%
#' dplyr::pull(guid) %>%
#' get_group_content(client, .)
#'
#' # Get permissions for all groups by passing in all group guids.
#' get_group_content(client, groups$guid)
#' }
#'
#' @family groups functions
#' @export
get_group_content <- function(src, guids) {
validate_R6_class(src, "Connect")
purrr::map_dfr(
guids,
~ get_one_groups_content(src = src, guid = .x)
)
}
get_one_groups_content <- function(src, guid) {
validate_R6_class(src, "Connect")
res <- src$group_content(guid)
if (length(res) == 0) {
return(tibble::tibble(
group_guid = NA_character_,
group_name = NA_character_,
content_guid = NA_character_,
content_name = NA_character_,
content_title = NA_character_,
access_type = NA_character_,
role = NA_character_
))
}
parsed <- parse_connectapi_typed(res, connectapi_ptypes$group_content)
permissions_df <- purrr::map_dfr(
parsed$permissions,
~ purrr::keep(
.x,
~ .x[["principal_guid"]] == guid
)
)
tibble::tibble(
group_guid = guid,
group_name = permissions_df$principal_name,
content_guid = parsed$content_guid,
content_name = parsed$content_name,
content_title = parsed$content_title,
access_type = parsed$access_type,
role = permissions_df$principal_role
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.