Skip to content

feat: add function to get integrations #426

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

Merged
merged 6 commits into from
Jul 28, 2025
Merged
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
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Collate:
'get.R'
'git.R'
'groups.R'
'integrations.R'
'lazy.R'
'page.R'
'parse.R'
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ S3method("[[",connect_tag_tree)
S3method(api_build,op_base_connect)
S3method(api_build,op_head)
S3method(as.data.frame,connect_list_hits)
S3method(as.data.frame,connect_list_integrations)
S3method(as.data.frame,tbl_connect)
S3method(as_tibble,connect_list_hits)
S3method(as_tibble,connect_list_integrations)
S3method(connect_vars,op_base)
S3method(connect_vars,op_single)
S3method(connect_vars,tbl_connect)
Expand Down Expand Up @@ -84,6 +86,7 @@ export(get_group_members)
export(get_group_permission)
export(get_groups)
export(get_image)
export(get_integrations)
export(get_job)
export(get_job_list)
export(get_jobs)
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- New `get_usage()` function returns content usage data from Connect's `GET
v1/instrumentation/content/hits` endpoint on Connect v2025.04.0 and higher.
(#390)
- New `get_integrations()` function lists all OAuth integrations available on the
Connect server from the `GET v1/oauth/integrations` endpoint on Connect v2024.12.0
and higher. (#413)

## Enhancements and fixes

Expand Down
4 changes: 4 additions & 0 deletions R/get.R
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,8 @@ get_procs <- function(src) {
#' Please see https://docs.posit.co/connect/user/oauth-integrations/#obtaining-a-viewer-oauth-access-token
#' for more information.
#'
#' @seealso [get_integrations()], [get_oauth_content_credentials()]
#'
#' @export
get_oauth_credentials <- function(
connect,
Expand Down Expand Up @@ -886,6 +888,8 @@ get_oauth_credentials <- function(
#' Please see https://docs.posit.co/connect/user/oauth-integrations/#obtaining-a-service-account-oauth-access-token
#' for more information.
#'
#' @seealso [get_integrations()], [get_oauth_credentials()]
#'
#' @export
get_oauth_content_credentials <- function(
connect,
Expand Down
106 changes: 106 additions & 0 deletions R/integrations.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#' List all OAuth integrations on the Connect server
#'
#' @description
#' Retrieve information about all OAuth integrations available to Posit Connect.
#' You must have administrator or publisher privileges to perform this action.
#'
#' @param client A `Connect` R6 client object.
#'
#' @return A list of OAuth integrations. Each integration is a list with the
#' following elements (all character strings unless indicated otherwise):
#'
#' * `id`: The internal identifier of this OAuth integration.
#' * `guid`: The GUID of this OAuth integration.
#' * `created_time`: The timestamp (RFC3339) indicating when this integration
#' was created.
#' * `updated_time`: The timestamp (RFC3339) indicating when this integration
#' was last updated
#' * `name`: A descriptive name to identify the OAuth integration.
#' * `description`: A brief text to describe the OAuth integration.
#' * `template`: The template used to configure this OAuth integration.
#' * `auth_type`: The authentication type indicates which OAuth flow is used by
#' this integration.
#' * `config`: A sub-list list with the OAuth integration configuration. Fields
#' differ between integrations.
#'
#' Use [as.data.frame()] or [tibble::as_tibble()] to convert to a data frame with
#' parsed types. In the resulting data frame:
#'
#' * `created_time` and `updated_time` are parsed to `POSIXct`.
#' * `config` remains as a list-column.
#'
#' @seealso [get_oauth_credentials()], [get_oauth_content_credentials()]
#'
#' @examples
#' \dontrun{
#' client <- connect()
#'
#' # Fetch all OAuth integrations
#' integrations <- get_integrations(client)
#'
#'
#' # Update the configuration and metadata for a subset of integrations.
#' json_payload <- toJSON(list(
#' description = "New Description",
#' config = list(
#' client_secret = "new-client-secret"
#' )
#' ), auto_unbox = TRUE)
#'
#' results <- integrations |>
#' purrr::keep(\(x) x$template == "service_to_update") |>
#' purrr::map(\(x) client$PATCH(paste0("v1/oauth/integrations/", x$guid), body = json_payload))
#'
#'
#' # Convert to tibble or data frame
#' integrations_df <- tibble::as_tibble(integrations)
#' }
#'
#' @export
get_integrations <- function(client) {
error_if_less_than(client$version, "2024.12.0")
integrations <- client$GET(v1_url("oauth", "integrations"))
class(integrations) <- c("connect_list_integrations", class(integrations))
integrations
}

#' Convert integrations data to a data frame
#'
#' @description
#' Converts an list returned by [get_integrations()] into a data frame.
#'
#' @param x A `connect_list_integrations` object (from [get_integrations()]).
#' @param row.names Passed to [base::as.data.frame()].
#' @param optional Passed to [base::as.data.frame()].
#' @param ... Passed to [base::as.data.frame()].
#'
#' @return A `data.frame` with one row per integration.
#' @export
as.data.frame.connect_list_integrations <- function(
x,
row.names = NULL, # nolint
optional = FALSE,
...
) {
integrations_tbl <- as_tibble(x)
as.data.frame(
integrations_tbl,
row.names = row.names,
optional = optional,
...
)
}

#' Convert integrations data to a tibble
#'
#' @description
#' Converts a list returned by [get_integrations()] to a tibble.
#'
#' @param x A `connect_list_integrations` object.
#' @param ... Unused.
#'
#' @return A tibble with one row per integration.
#' @export
as_tibble.connect_list_integrations <- function(x, ...) {
parse_connectapi_typed(x, connectapi_ptypes$integrations)
}
11 changes: 11 additions & 0 deletions R/ptype.R
Original file line number Diff line number Diff line change
Expand Up @@ -271,5 +271,16 @@ connectapi_ptypes <- list(
name = NA_character_,
version = NA_character_,
hash = NA_character_
),
integrations = tibble::tibble(
id = NA_character_,
guid = NA_character_,
created_time = NA_datetime_,
updated_time = NA_datetime_,
name = NA_character_,
description = NA_character_,
template = NA_character_,
auth_type = NA_character_,
config = NA_list_
)
)
2 changes: 2 additions & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ reference:
- starts_with("get")
- as.data.frame.connect_list_hits
- as_tibble.connect_list_hits
- as.data.frame.connect_list_integrations
- as_tibble.connect_list_integrations

- title: "Other"
desc: >
Expand Down
23 changes: 23 additions & 0 deletions man/as.data.frame.connect_list_integrations.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions man/as_tibble.connect_list_integrations.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions man/get_integrations.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions man/get_oauth_content_credentials.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions man/get_oauth_credentials.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/testthat/2024.12.0/__api__/server_settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "2024.12.0"
}
38 changes: 38 additions & 0 deletions tests/testthat/2024.12.0/__api__/v1/oauth/integrations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"id": "4",
"guid": "f8688548",
"created_time": "2024-08-01T20:14:31Z",
"updated_time": "2025-03-25T19:08:26Z",
"name": "GitHub Integration",
"description": "with refresh support ",
"template": "custom",
"auth_type": "Viewer",
"config": {
"auth_mode": "Confidential",
"auth_type": "Viewer",
"authorization_uri": "https://github.com/login/oauth/authorize",
"client_id": "client_id_123",
"scopes": "offline_access openid profile email repo read:user",
"token_endpoint_auth_method": "client_secret_post",
"token_uri": "https://github.com/login/oauth/access_token",
"use_pkce": true
}
},
{
"id": "5",
"guid": "cacc0cf1",
"created_time": "2024-09-09T15:01:29Z",
"updated_time": "2025-03-25T19:07:01Z",
"name": "Example Service",
"description": "The service provides utility to your company",
"template": "generic_service",
"auth_type": "Viewer",
"config": {
"account_url": "https://service.example.com",
"auth_mode": "Confidential",
"client_id": "client_id_456",
"scopes": "refresh_token"
}
}
]
3 changes: 3 additions & 0 deletions tests/testthat/2024.12.0/__ping__.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{

}
Loading
Loading