diff --git a/NAMESPACE b/NAMESPACE index 9abd8b71..889d578a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -134,6 +134,7 @@ export(repo_check_branches) export(repo_check_branches_ref) export(repo_check_manifest_dirs) export(schedule_describe) +export(search_content) export(set_content_tag_tree) export(set_content_tags) export(set_environment_all) diff --git a/NEWS.md b/NEWS.md index 5ed138ec..0624c691 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ - New functions allow you to manage the OAuth integrations on your Connect server: `create_integration()`, `update_integration()` and `delete_integration()`. (#434) +- Support content search API with the `search_content()` function. (#272) # connectapi 0.8.0 diff --git a/R/content.R b/R/content.R index c2dca338..b7c04cab 100644 --- a/R/content.R +++ b/R/content.R @@ -1434,3 +1434,174 @@ get_content_packages <- function(content) { res <- content$packages() parse_connectapi_typed(res, connectapi_ptypes$content_packages) } + +#' Search for content on the Connect server +#' +#' @param client A Connect object +#' @param q The search query, using the syntax described in the Connect +#' documentation on [content search +#' terms](https://docs.posit.co/connect/user/viewing-content/#searching-content) +#' @param page_number Integer. The page to return relative to the given `page_size`. +#' Must be greater than 0. +#' @param page_size Integer. The number of items to include in each page. This +#' parameter is "best effort" since there may not be enough results to honor the +#' request. If `page_size` is less than 1 or greater than 500, an error will be +#' returned. +#' @param include Comma-separated character string of values indicating additional +#' details to include in the response. Values can be `owner` and `vanity_url`; +#' both are included by default. +#' @param ... Extra arguments. Currently not used. +#' +#' @return +#' A list containing sub-fields: +#' * `total`: The total number of results. +#' * `results`: A list of lists representing content items on Connect. +#' +#' Each piece of content contains the following fields: +#' * `guid`: The unique identifier of this content item. +#' * `name`: A simple, URL-friendly identifier. Allows alpha-numeric +#' characters, hyphens ("-"), and underscores ("_"). +#' * `title`: The title of this content. +#' * `description`: A rich description of this content +#' * `access_type`: Access type describes how this content manages its +#' viewers. It may have a value of `all`, `logged_in` or `acl`. +#' The value `all` is the most permissive; any visitor to Posit +#' Connect will be able to view this content. The value `logged_in` +#' indicates that all Posit Connect accounts may view the content. The +#' `acl` value lets specifically enumerated users and groups view the +#' content. Users configured as collaborators may always view content. +#' * `connection_timeout`: Maximum number of seconds allowed without data +#' sent or received across a client connection. A value of 0 means +#' connections will never time-out (not recommended). When null, the +#' default `Scheduler.ConnectionTimeout` is used. Applies only to content +#' types that are executed on demand. +#' * `read_timeout`: Maximum number of seconds allowed without data received +#' from a client connection. A value of 0 means a lack of client (browser) +#' interaction never causes the connection to close. When null, the default +#' `Scheduler.ReadTimeout` is used. Applies only to content types that are +#' executed on demand. +#' * `init_timeout`: The maximum number of seconds allowed for an interactive +#' application to start. Posit Connect must be able to connect +#' to a newly launched Shiny application, for example, before this threshold +#' has elapsed. When null, the default `Scheduler.InitTimeout` is +#' used. Applies only to content types that are executed on demand. +#' * `idle_timeout`: The maximum number of seconds a worker process +#' for an interactive application to remain alive after it goes idle (no +#' active connections). When null, the default `Scheduler.IdleTimeout` +#' is used. Applies only to content types that are executed on demand. +#' * `max_processes`: Specifies the total number of concurrent processes +#' allowed for a single interactive application. When null, the +#' default `Scheduler.MaxProcesses` setting is used. Applies only to +#' content types that are executed on demand. +#' * `min_processes`: Specifies the minimum number of concurrent +#' processes allowed for a single interactive application. When null, the +#' default `Scheduler.MinProcesses` is used. Applies only to content types +#' that are executed on demand. +#' * `max_conns_per_process`: Specifies the maximum number of +#' client connections allowed to an individual process. Incoming connections +#' which will exceed this limit are routed to a new process or rejected. +#' When null, the default `Scheduler.MaxConnsPerProcess` is used. Applies +#' only to content types that are executed on demand. +#' * `load_factor`: Controls how aggressively new processes are spawned. +#' When null, the default `Scheduler.LoadFactor` is used. Applies only to +#' content types that are executed on demand. +#' * `created_time`: The timestamp (RFC3339) indicating when this +#' content was created. +#' * `last_deployed_time`: The timestamp (RFC3339) indicating when +#' this content last had a successful bundle deployment performed. +#' * `bundle_id`: The identifier for the active deployment bundle. +#' Automatically assigned upon the successful deployment of that bundle. +#' * `app_mode`: The runtime model for this content. Has a value +#' of `unknown` before data is deployed to this item. Automatically assigned +#' upon the first successful bundle deployment. Allowed: `api`, +#' `jupyter-static`, `python-api`, `python-bokeh`, `python-dash`, +#' `python-streamlit`, `rmd-shiny`, `rmd-static`, `shiny`, `static`, +#' `tensorflow-saved-model`, `unknown`. +#' * `content_category`: Describes the specialization of the content +#' runtime model. Automatically assigned upon the first successful bundle +#' deployment. +#' * `parameterized`: True when R Markdown rendered content +#' allows parameter configuration. Automatically assigned upon the first +#' successful bundle deployment. Applies only to content with an app_mode +#' of rmd-static. +#' * `r_version`: The version of the R interpreter associated +#' with this content. The value null represents that an R interpreter is +#' not used by this content or that the R package environment has not been +#' successfully restored. Automatically assigned upon the successful +#' deployment of a bundle. +#' * `py_version`: The version of the Python interpreter +#' associated with this content. The value null represents that a Python +#' interpreter is not used by this content or that the Python package +#' environment has not been successfully restored. Automatically assigned +#' upon the successful deployment of a bundle. +#' * `run_as`: The UNIX user that executes this content. +#' When null, the default Applications.RunAs is used. Applies +#' only to executable content types - not static. +#' * `run_as_current_user`: Indicates if this content is allowed +#' to execute as the logged-in user when using PAM authentication. +#' Applies only to executable content types - not static. +#' * `owner_guid`: The unique identifier for the owner +#' * `content_url`: The URL associated with this content. Computed +#' from the GUID for this content. +#' * `dashboard_url`: The URL within the Connect dashboard where +#' this content can be configured. Computed from the GUID for this content. +#' * `role`: The relationship of the accessing user to this +#' content. A value of owner is returned for the content owner. editor +#' indicates a collaborator. The viewer value is given to users who are +#' permitted to view the content. A none role is returned for +#' administrators who cannot view the content but are permitted to view +#' its configuration. Computed at the time of the request. +#' * `vanity_url`: The vanity URL associated with this content item. +#' * `id`: The internal numeric identifier of this content item. +#' * `tags`: Tags associated with this content item. Each entry is a list +#' with the following fields: +#' * `id`: The identifier for the tag. +#' * `name`: The name of the tag. +#' * `parent_id`: The identifier for the parent tag. Null if the tag is a +#' top-level tag. +#' * `created_time`: The timestamp (RFC3339) indicating when the tag was +#' created. +#' * `updated_time`: The timestamp (RFC3339) indicating when the tag was +#' last updated. +#' * `owner`: Basic details about the owner of this content item. Each entry +#' is a list with the following fields: +#' * `guid`: The user's GUID, or unique identifier, in UUID RFC4122 format. +#' * `username`: The user's username. +#' * `first_name`: The user's first name. +#' * `last_name`: The user's last name. +#' +#' @details +#' Please see https://docs.posit.co/connect/api/#get-/v1/search/content for more +#' information. +#' +#' @examples +#' \dontrun{ +#' library(connectapi) +#' client <- connect() +#' +#' search_content(client, q = "") +#' } +#' +#' @family content functions +#' @export +search_content <- function( + client, + q = NULL, + page_number = 1, + page_size = 500, + include = "owner,vanity_url", + ... +) { + error_if_less_than(client$version, "2024.04.0") + + path <- v1_url("search", "content") + + query <- list( + q = q, + page_number = page_number, + page_size = page_size, + include = include + ) + + client$GET(path, query = query) +} diff --git a/man/content_delete.Rd b/man/content_delete.Rd index 49c25890..5ee40beb 100644 --- a/man/content_delete.Rd +++ b/man/content_delete.Rd @@ -40,6 +40,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/content_item.Rd b/man/content_item.Rd index e66b941a..e6398dc5 100644 --- a/man/content_item.Rd +++ b/man/content_item.Rd @@ -46,6 +46,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/content_title.Rd b/man/content_title.Rd index b709ef12..5ddda690 100644 --- a/man/content_title.Rd +++ b/man/content_title.Rd @@ -42,6 +42,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/content_update.Rd b/man/content_update.Rd index 2763e308..02e35373 100644 --- a/man/content_update.Rd +++ b/man/content_update.Rd @@ -62,6 +62,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/create_random_name.Rd b/man/create_random_name.Rd index dfea5099..25915846 100644 --- a/man/create_random_name.Rd +++ b/man/create_random_name.Rd @@ -39,6 +39,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/dashboard_url.Rd b/man/dashboard_url.Rd index cd14e177..b9ae6b9d 100644 --- a/man/dashboard_url.Rd +++ b/man/dashboard_url.Rd @@ -39,6 +39,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/delete_thumbnail.Rd b/man/delete_thumbnail.Rd index 5a7ecbef..2c7c0895 100644 --- a/man/delete_thumbnail.Rd +++ b/man/delete_thumbnail.Rd @@ -50,6 +50,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/delete_vanity_url.Rd b/man/delete_vanity_url.Rd index 0d18b3d4..ad21043c 100644 --- a/man/delete_vanity_url.Rd +++ b/man/delete_vanity_url.Rd @@ -34,6 +34,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/deploy_repo.Rd b/man/deploy_repo.Rd index 3e6772e0..f1f879b6 100644 --- a/man/deploy_repo.Rd +++ b/man/deploy_repo.Rd @@ -77,6 +77,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/environment.Rd b/man/environment.Rd index 0aac5576..b4ca8dbb 100644 --- a/man/environment.Rd +++ b/man/environment.Rd @@ -59,6 +59,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_associations.Rd b/man/get_associations.Rd index c2c762ad..c03e8b73 100644 --- a/man/get_associations.Rd +++ b/man/get_associations.Rd @@ -76,6 +76,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_bundles.Rd b/man/get_bundles.Rd index fd885f88..28bdd93f 100644 --- a/man/get_bundles.Rd +++ b/man/get_bundles.Rd @@ -39,6 +39,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, @@ -70,6 +71,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_image.Rd b/man/get_image.Rd index 98db6ee7..90508762 100644 --- a/man/get_image.Rd +++ b/man/get_image.Rd @@ -49,6 +49,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_job.Rd b/man/get_job.Rd index 6c138033..0d4654ef 100644 --- a/man/get_job.Rd +++ b/man/get_job.Rd @@ -43,6 +43,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_jobs.Rd b/man/get_jobs.Rd index 75b43e38..b7cfd9b3 100644 --- a/man/get_jobs.Rd +++ b/man/get_jobs.Rd @@ -118,6 +118,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_log.Rd b/man/get_log.Rd index 72cd8cb3..07ea7540 100644 --- a/man/get_log.Rd +++ b/man/get_log.Rd @@ -65,6 +65,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_thumbnail.Rd b/man/get_thumbnail.Rd index afad4c30..6063b628 100644 --- a/man/get_thumbnail.Rd +++ b/man/get_thumbnail.Rd @@ -55,6 +55,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/get_vanity_url.Rd b/man/get_vanity_url.Rd index 08718d50..7653ded6 100644 --- a/man/get_vanity_url.Rd +++ b/man/get_vanity_url.Rd @@ -37,6 +37,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/git.Rd b/man/git.Rd index b11defae..4173ac67 100644 --- a/man/git.Rd +++ b/man/git.Rd @@ -62,6 +62,7 @@ Other content functions: \code{\link{get_vanity_url}()}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/has_thumbnail.Rd b/man/has_thumbnail.Rd index 99b79b38..cf2b1897 100644 --- a/man/has_thumbnail.Rd +++ b/man/has_thumbnail.Rd @@ -51,6 +51,7 @@ Other content functions: \code{\link{get_vanity_url}()}, \code{\link{git}}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/permissions.Rd b/man/permissions.Rd index 2e9e2b20..40604e2d 100644 --- a/man/permissions.Rd +++ b/man/permissions.Rd @@ -84,6 +84,7 @@ Other content functions: \code{\link{get_vanity_url}()}, \code{\link{git}}, \code{\link{has_thumbnail}()}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/search_content.Rd b/man/search_content.Rd new file mode 100644 index 00000000..5fa2b507 --- /dev/null +++ b/man/search_content.Rd @@ -0,0 +1,211 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/content.R +\name{search_content} +\alias{search_content} +\title{Search for content on the Connect server} +\usage{ +search_content( + client, + q = NULL, + page_number = 1, + page_size = 500, + include = "owner,vanity_url", + ... +) +} +\arguments{ +\item{client}{A Connect object} + +\item{q}{The search query, using the syntax described in the Connect +documentation on \href{https://docs.posit.co/connect/user/viewing-content/#searching-content}{content search terms}} + +\item{page_number}{Integer. The page to return relative to the given \code{page_size}. +Must be greater than 0.} + +\item{page_size}{Integer. The number of items to include in each page. This +parameter is "best effort" since there may not be enough results to honor the +request. If \code{page_size} is less than 1 or greater than 500, an error will be +returned.} + +\item{include}{Comma-separated character string of values indicating additional +details to include in the response. Values can be \code{owner} and \code{vanity_url}; +both are included by default.} + +\item{...}{Extra arguments. Currently not used.} +} +\value{ +A list containing sub-fields: +\itemize{ +\item \code{total}: The total number of results. +\item \code{results}: A list of lists representing content items on Connect. +} + +Each piece of content contains the following fields: +\itemize{ +\item \code{guid}: The unique identifier of this content item. +\item \code{name}: A simple, URL-friendly identifier. Allows alpha-numeric +characters, hyphens ("-"), and underscores ("_"). +\item \code{title}: The title of this content. +\item \code{description}: A rich description of this content +\item \code{access_type}: Access type describes how this content manages its +viewers. It may have a value of \code{all}, \code{logged_in} or \code{acl}. +The value \code{all} is the most permissive; any visitor to Posit +Connect will be able to view this content. The value \code{logged_in} +indicates that all Posit Connect accounts may view the content. The +\code{acl} value lets specifically enumerated users and groups view the +content. Users configured as collaborators may always view content. +\item \code{connection_timeout}: Maximum number of seconds allowed without data +sent or received across a client connection. A value of 0 means +connections will never time-out (not recommended). When null, the +default \code{Scheduler.ConnectionTimeout} is used. Applies only to content +types that are executed on demand. +\item \code{read_timeout}: Maximum number of seconds allowed without data received +from a client connection. A value of 0 means a lack of client (browser) +interaction never causes the connection to close. When null, the default +\code{Scheduler.ReadTimeout} is used. Applies only to content types that are +executed on demand. +\item \code{init_timeout}: The maximum number of seconds allowed for an interactive +application to start. Posit Connect must be able to connect +to a newly launched Shiny application, for example, before this threshold +has elapsed. When null, the default \code{Scheduler.InitTimeout} is +used. Applies only to content types that are executed on demand. +\item \code{idle_timeout}: The maximum number of seconds a worker process +for an interactive application to remain alive after it goes idle (no +active connections). When null, the default \code{Scheduler.IdleTimeout} +is used. Applies only to content types that are executed on demand. +\item \code{max_processes}: Specifies the total number of concurrent processes +allowed for a single interactive application. When null, the +default \code{Scheduler.MaxProcesses} setting is used. Applies only to +content types that are executed on demand. +\item \code{min_processes}: Specifies the minimum number of concurrent +processes allowed for a single interactive application. When null, the +default \code{Scheduler.MinProcesses} is used. Applies only to content types +that are executed on demand. +\item \code{max_conns_per_process}: Specifies the maximum number of +client connections allowed to an individual process. Incoming connections +which will exceed this limit are routed to a new process or rejected. +When null, the default \code{Scheduler.MaxConnsPerProcess} is used. Applies +only to content types that are executed on demand. +\item \code{load_factor}: Controls how aggressively new processes are spawned. +When null, the default \code{Scheduler.LoadFactor} is used. Applies only to +content types that are executed on demand. +\item \code{created_time}: The timestamp (RFC3339) indicating when this +content was created. +\item \code{last_deployed_time}: The timestamp (RFC3339) indicating when +this content last had a successful bundle deployment performed. +\item \code{bundle_id}: The identifier for the active deployment bundle. +Automatically assigned upon the successful deployment of that bundle. +\item \code{app_mode}: The runtime model for this content. Has a value +of \code{unknown} before data is deployed to this item. Automatically assigned +upon the first successful bundle deployment. Allowed: \code{api}, +\code{jupyter-static}, \code{python-api}, \code{python-bokeh}, \code{python-dash}, +\code{python-streamlit}, \code{rmd-shiny}, \code{rmd-static}, \code{shiny}, \code{static}, +\code{tensorflow-saved-model}, \code{unknown}. +\item \code{content_category}: Describes the specialization of the content +runtime model. Automatically assigned upon the first successful bundle +deployment. +\item \code{parameterized}: True when R Markdown rendered content +allows parameter configuration. Automatically assigned upon the first +successful bundle deployment. Applies only to content with an app_mode +of rmd-static. +\item \code{r_version}: The version of the R interpreter associated +with this content. The value null represents that an R interpreter is +not used by this content or that the R package environment has not been +successfully restored. Automatically assigned upon the successful +deployment of a bundle. +\item \code{py_version}: The version of the Python interpreter +associated with this content. The value null represents that a Python +interpreter is not used by this content or that the Python package +environment has not been successfully restored. Automatically assigned +upon the successful deployment of a bundle. +\item \code{run_as}: The UNIX user that executes this content. +When null, the default Applications.RunAs is used. Applies +only to executable content types - not static. +\item \code{run_as_current_user}: Indicates if this content is allowed +to execute as the logged-in user when using PAM authentication. +Applies only to executable content types - not static. +\item \code{owner_guid}: The unique identifier for the owner +\item \code{content_url}: The URL associated with this content. Computed +from the GUID for this content. +\item \code{dashboard_url}: The URL within the Connect dashboard where +this content can be configured. Computed from the GUID for this content. +\item \code{role}: The relationship of the accessing user to this +content. A value of owner is returned for the content owner. editor +indicates a collaborator. The viewer value is given to users who are +permitted to view the content. A none role is returned for +administrators who cannot view the content but are permitted to view +its configuration. Computed at the time of the request. +\item \code{vanity_url}: The vanity URL associated with this content item. +\item \code{id}: The internal numeric identifier of this content item. +\item \code{tags}: Tags associated with this content item. Each entry is a list +with the following fields: +\itemize{ +\item \code{id}: The identifier for the tag. +\item \code{name}: The name of the tag. +\item \code{parent_id}: The identifier for the parent tag. Null if the tag is a +top-level tag. +\item \code{created_time}: The timestamp (RFC3339) indicating when the tag was +created. +\item \code{updated_time}: The timestamp (RFC3339) indicating when the tag was +last updated. +} +\item \code{owner}: Basic details about the owner of this content item. Each entry +is a list with the following fields: +\itemize{ +\item \code{guid}: The user's GUID, or unique identifier, in UUID RFC4122 format. +\item \code{username}: The user's username. +\item \code{first_name}: The user's first name. +\item \code{last_name}: The user's last name. +} +} +} +\description{ +Search for content on the Connect server +} +\details{ +Please see https://docs.posit.co/connect/api/#get-/v1/search/content for more +information. +} +\examples{ +\dontrun{ +library(connectapi) +client <- connect() + +search_content(client, q = "") +} + +} +\seealso{ +Other content functions: +\code{\link{content_delete}()}, +\code{\link{content_item}()}, +\code{\link{content_title}()}, +\code{\link{content_update}()}, +\code{\link{create_random_name}()}, +\code{\link{dashboard_url}()}, +\code{\link{delete_thumbnail}()}, +\code{\link{delete_vanity_url}()}, +\code{\link{deploy_repo}()}, +\code{\link{get_associations}()}, +\code{\link{get_bundles}()}, +\code{\link{get_environment}()}, +\code{\link{get_image}()}, +\code{\link{get_job}()}, +\code{\link{get_jobs}()}, +\code{\link{get_log}()}, +\code{\link{get_thumbnail}()}, +\code{\link{get_vanity_url}()}, +\code{\link{git}}, +\code{\link{has_thumbnail}()}, +\code{\link{permissions}}, +\code{\link{set_image_path}()}, +\code{\link{set_integrations}()}, +\code{\link{set_run_as}()}, +\code{\link{set_thumbnail}()}, +\code{\link{set_vanity_url}()}, +\code{\link{swap_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, +\code{\link{terminate_jobs}()}, +\code{\link{verify_content_name}()} +} +\concept{content functions} diff --git a/man/set_image.Rd b/man/set_image.Rd index 394efea6..9486f24b 100644 --- a/man/set_image.Rd +++ b/man/set_image.Rd @@ -56,6 +56,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, \code{\link{set_thumbnail}()}, diff --git a/man/set_integrations.Rd b/man/set_integrations.Rd index 615f8ebd..3ad43cc6 100644 --- a/man/set_integrations.Rd +++ b/man/set_integrations.Rd @@ -77,6 +77,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_run_as}()}, \code{\link{set_thumbnail}()}, diff --git a/man/set_run_as.Rd b/man/set_run_as.Rd index 3e6e72b5..8485fa3d 100644 --- a/man/set_run_as.Rd +++ b/man/set_run_as.Rd @@ -58,6 +58,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_thumbnail}()}, diff --git a/man/set_thumbnail.Rd b/man/set_thumbnail.Rd index 458623e1..79cdab25 100644 --- a/man/set_thumbnail.Rd +++ b/man/set_thumbnail.Rd @@ -55,6 +55,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/set_vanity_url.Rd b/man/set_vanity_url.Rd index 92bb3ae1..2fd323cc 100644 --- a/man/set_vanity_url.Rd +++ b/man/set_vanity_url.Rd @@ -51,6 +51,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/swap_vanity_url.Rd b/man/swap_vanity_url.Rd index f8b89996..7d75b43d 100644 --- a/man/swap_vanity_url.Rd +++ b/man/swap_vanity_url.Rd @@ -41,6 +41,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/swap_vanity_urls.Rd b/man/swap_vanity_urls.Rd index acd488a9..1d69e651 100644 --- a/man/swap_vanity_urls.Rd +++ b/man/swap_vanity_urls.Rd @@ -40,6 +40,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/terminate_jobs.Rd b/man/terminate_jobs.Rd index 3764fbe7..308d77ce 100644 --- a/man/terminate_jobs.Rd +++ b/man/terminate_jobs.Rd @@ -68,6 +68,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/man/verify_content_name.Rd b/man/verify_content_name.Rd index bc1774f8..c2f04ce4 100644 --- a/man/verify_content_name.Rd +++ b/man/verify_content_name.Rd @@ -43,6 +43,7 @@ Other content functions: \code{\link{git}}, \code{\link{has_thumbnail}()}, \code{\link{permissions}}, +\code{\link{search_content}()}, \code{\link{set_image_path}()}, \code{\link{set_integrations}()}, \code{\link{set_run_as}()}, diff --git a/tests/testthat/2025.09.0/__api__/server_settings.json b/tests/testthat/2025.09.0/__api__/server_settings.json new file mode 100644 index 00000000..db784321 --- /dev/null +++ b/tests/testthat/2025.09.0/__api__/server_settings.json @@ -0,0 +1,3 @@ +{ + "version": "2025.09.0" +} \ No newline at end of file diff --git a/tests/testthat/2025.09.0/__api__/v1/search/content-0f26be.json b/tests/testthat/2025.09.0/__api__/v1/search/content-0f26be.json new file mode 100644 index 00000000..5bdf3d30 --- /dev/null +++ b/tests/testthat/2025.09.0/__api__/v1/search/content-0f26be.json @@ -0,0 +1,117 @@ +{ + "total": 2, + "results": [ + { + "guid": "c9f68287", + "name": "sea-bream-report", + "title": "sea bream report", + "description": "", + "access_type": "all", + "locked": false, + "locked_message": "", + "connection_timeout": null, + "read_timeout": null, + "init_timeout": null, + "idle_timeout": null, + "max_processes": null, + "min_processes": null, + "max_conns_per_process": null, + "load_factor": null, + "memory_request": null, + "memory_limit": null, + "cpu_request": null, + "cpu_limit": null, + "amd_gpu_limit": null, + "nvidia_gpu_limit": null, + "service_account_name": null, + "default_image_name": null, + "default_environment_guid": null, + "created_time": "2024-08-29T17:52:30Z", + "last_deployed_time": "2025-09-25T17:26:05Z", + "bundle_id": "306864", + "app_mode": "python-shiny", + "content_category": "", + "parameterized": false, + "environment_guid": null, + "cluster_name": "Local", + "image_name": null, + "r_version": null, + "py_version": "3.10.17", + "quarto_version": null, + "r_environment_management": null, + "default_r_environment_management": null, + "py_environment_management": true, + "default_py_environment_management": null, + "run_as": null, + "run_as_current_user": false, + "owner_guid": "c2250bb4", + "content_url": "https://connect.example/content/c9f68287/", + "dashboard_url": "https://connect.example/connect/#/apps/c9f68287", + "app_role": "none", + "id": "57138", + "owner": { + "guid": "c2250bb4", + "username": "toph_allen", + "first_name": "Toph", + "last_name": "Allen" + }, + "public_content_status": null + }, + { + "guid": "53032a0e", + "name": "sea-bream-dashboard", + "title": "sea bream dashboard", + "description": "", + "access_type": "all", + "locked": false, + "locked_message": "", + "connection_timeout": null, + "read_timeout": null, + "init_timeout": null, + "idle_timeout": null, + "max_processes": null, + "min_processes": null, + "max_conns_per_process": null, + "load_factor": null, + "memory_request": null, + "memory_limit": null, + "cpu_request": null, + "cpu_limit": null, + "amd_gpu_limit": null, + "nvidia_gpu_limit": null, + "service_account_name": null, + "default_image_name": null, + "default_environment_guid": null, + "created_time": "2024-08-29T17:49:34Z", + "last_deployed_time": "2025-09-25T17:23:21Z", + "bundle_id": "306844", + "app_mode": "python-shiny", + "content_category": "", + "parameterized": false, + "environment_guid": null, + "cluster_name": "Local", + "image_name": null, + "r_version": null, + "py_version": "3.10.17", + "quarto_version": null, + "r_environment_management": null, + "default_r_environment_management": null, + "py_environment_management": true, + "default_py_environment_management": null, + "run_as": null, + "run_as_current_user": false, + "owner_guid": "c2250bb4", + "content_url": "https://connect.example/content/53032a0e/", + "dashboard_url": "https://connect.example/connect/#/apps/53032a0e", + "app_role": "none", + "id": "57137", + "owner": { + "guid": "c2250bb4", + "username": "toph_allen", + "first_name": "Toph", + "last_name": "Allen" + }, + "public_content_status": null + } + ] +} diff --git a/tests/testthat/2025.09.0/__ping__.json b/tests/testthat/2025.09.0/__ping__.json new file mode 100644 index 00000000..0db3279e --- /dev/null +++ b/tests/testthat/2025.09.0/__ping__.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/tests/testthat/test-content.R b/tests/testthat/test-content.R index eb29015e..4047953e 100644 --- a/tests/testthat/test-content.R +++ b/tests/testthat/test-content.R @@ -466,3 +466,55 @@ test_that("get_content_packages() gets packages", { ) }) }) + +# content search ---- + +with_mock_dir("2025.09.0", { + client <- Connect$new( + server = "https://connect.example", + api_key = "not-a-key" + ) + + test_that("content search returns the expected list of content", { + res <- search_content(client, q = "sea bream") + expect_equal( + purrr::map_chr(res$results, "owner_guid"), + c("c2250bb4", "c2250bb4") + ) + expect_equal( + purrr::map_chr(res$results, "title"), + c("sea bream report", "sea bream dashboard") + ) + }) + + test_that("content search passes all parameters through correctly", { + without_internet( + expect_GET( + search_content( + client, + q = "bream", + include = "owner", + page_number = 2, + page_size = 5 + ), + "https://connect.example/__api__/v1/search/content?q=bream&page_number=2&page_size=5&include=owner" + ) + ) + }) +}) + +test_that("content search errors on Connect < 2024.04.0", { + client <- MockConnect$new("2024.04.0") + client$mock_response( + "GET", + "v1/search/content", + content = list() + ) + expect_no_error(search_content(client)) + + client <- MockConnect$new("2024.03.0") + expect_error( + search_content(client), + "ERROR: This feature requires Posit Connect version 2024.04.0 but you are using 2024.03.0." + ) +})