diff --git a/NAMESPACE b/NAMESPACE index c0968e5c..9cc4a581 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -141,6 +141,7 @@ export(set_schedule_year) export(set_thumbnail) export(set_vanity_url) export(swap_vanity_url) +export(swap_vanity_urls) export(tbl_connect) export(terminate_jobs) export(user_guid_from_username) diff --git a/NEWS.md b/NEWS.md index 02db3a14..e36f8644 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,10 +10,19 @@ client with permissions scoped to the content visitor when running on a Connect server. (#362) +## Enhancements and fixes + +- `swap_vanity_urls()` can correctly perform a swap involving a content item + with no vanity URL. (#360) +- `swap_vanity_urls()` handles permissions errors gracefully, attempting to roll + back any changes made. (#360) + ## Newly deprecated - `get_job()` (singular) is now deprecated, its functionality taken care of by other functions, including `get_log()`. +- `swap_vanity_url(old, new)` has been deprecated and renamed to + `swap_vanity_urls(content_a, content_b)`. # connectapi 0.5.0 diff --git a/R/deploy.R b/R/deploy.R index 796d6fed..120bbf5b 100644 --- a/R/deploy.R +++ b/R/deploy.R @@ -413,7 +413,7 @@ deploy_current <- function(content) { #' Set the Vanity URL #' -#' Sets the Vanity URL for a piece of content. +#' Set the vanity URL for a piece of content. #' #' @param content A Content object #' @param url The path component of the URL @@ -453,7 +453,7 @@ set_vanity_url <- function(content, url, force = FALSE) { #' Delete the Vanity URL #' -#' Deletes the Vanity URL for a piece of content. +#' Delete the vanity URL for a piece of content. #' #' @param content A Content object #' @@ -464,14 +464,14 @@ delete_vanity_url <- function(content) { error_if_less_than(con$version, "1.8.6") guid <- content$get_content()$guid - con$DELETE(v1_url("content", guid, "vanity")) + con$DELETE(v1_url("content", guid, "vanity"), parser = "parsed") content } #' Get the Vanity URL #' -#' Gets the Vanity URL for a piece of content. +#' Get the vanity URL for a piece of content. #' #' @param content A Content object #' @@ -501,55 +501,80 @@ get_vanity_url <- function(content) { return(van$path) } -#' Swap the Vanity URL +#' Swap Vanity URLs #' -#' Swaps the Vanity URLs between two pieces of content +#' Swap the vanity URLs of two pieces of content. #' -#' @param from_content A Content object -#' @param to_content A Content object +#' @param content_a A Content object +#' @param content_b A Content object +#' +#' @returns A list of the new vanity URLs for `content_a` and `content_b` #' #' @family content functions #' @export -swap_vanity_url <- function(from_content, to_content) { - warn_experimental("swap_vanity_url") - scoped_experimental_silence() +swap_vanity_urls <- function(content_a, content_b) { # TODO: Add prompt if in an interactive session # TODO: Add pretty print output of what is happening - # TODO: Test error cases super thoroughly!! - # TODO: Do a "dry run" of sorts...? Check privileges... etc... - # TODO: Do the changes within a TryCatch so we can undo...? - # TODO: Need a way to "unset" a vanity URL - - from_vanity <- get_vanity_url(from_content) - to_vanity <- get_vanity_url(to_content) - if (is.null(from_vanity) && is.null(to_vanity)) { - warning("Neither content has a Vanity URL. Exiting") - } else { - # swapping vanity URLs - tmp_vanity <- paste0("vanity-url-swap-", create_random_name(length = 50)) + validate_R6_class(content_a, "Content") + validate_R6_class(content_b, "Content") - if (!is.null(from_vanity)) { - set_vanity_url(from_content, tmp_vanity) - } else { - set_vanity_url(to_content, tmp_vanity) - } + vanity_a <- get_vanity_url(content_a) + vanity_b <- get_vanity_url(content_b) - if (!is.null(from_vanity)) { - set_vanity_url(to_content, from_vanity) + if (is.null(vanity_a) && is.null(vanity_b)) { + warning("Neither content has a vanity URL") + } else { + tryCatch( + delete_vanity_url(content_a), + error = function(e) { + stop("Unable to modify the vanity URL for content_a: ", e$message, call. = FALSE) + } + ) + tryCatch( + delete_vanity_url(content_b), + error = function(e) { + set_vanity_url(content_a, vanity_a) + stop("Unable to modify the vanity URL for content_b: ", e$message, call. = FALSE) + } + ) + if (!is.null(vanity_a)) { + set_vanity_url(content_b, vanity_a) } - if (!is.null(to_vanity)) { - set_vanity_url(from_content, to_vanity) + if (!is.null(vanity_b)) { + set_vanity_url(content_a, vanity_b) } - - from_vanity <- get_vanity_url(from_content) - to_vanity <- get_vanity_url(to_content) + vanity_a <- get_vanity_url(content_a) + vanity_b <- get_vanity_url(content_b) } return( list( - from = from_vanity, - to = to_vanity + content_a = vanity_a, + content_b = vanity_b + ) + ) +} + +#' Swap Vanity URLs +#' +#' Swap the vanity URLs of two pieces of content. +#' This function is deprecated; please use \code{\link{swap_vanity_urls}}. +#' +#' @param from A Content object +#' @param to A Content object +#' +#' @returns A list of the new vanity URLs for `from` and `to` +#' +#' @family content functions +#' @export +swap_vanity_url <- function(from, to) { + lifecycle::deprecate_warn("0.6.0", "swap_vanity_url()", "swap_vanity_urls()") + res <- swap_vanity_urls(from, to) + return( + list( + from = res[["content_a"]], + to = res[["content_b"]] ) ) } diff --git a/man/content_delete.Rd b/man/content_delete.Rd index 7426166d..182d7226 100644 --- a/man/content_delete.Rd +++ b/man/content_delete.Rd @@ -45,6 +45,7 @@ Other content functions: \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}()} } diff --git a/man/content_item.Rd b/man/content_item.Rd index 79294792..ae0dda8b 100644 --- a/man/content_item.Rd +++ b/man/content_item.Rd @@ -51,6 +51,7 @@ Other content functions: \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}()} } diff --git a/man/content_title.Rd b/man/content_title.Rd index be347cd7..983c829e 100644 --- a/man/content_title.Rd +++ b/man/content_title.Rd @@ -47,6 +47,7 @@ Other content functions: \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}()} } diff --git a/man/content_update.Rd b/man/content_update.Rd index 8116acba..dfbad0b4 100644 --- a/man/content_update.Rd +++ b/man/content_update.Rd @@ -67,6 +67,7 @@ Other content functions: \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}()} } diff --git a/man/create_random_name.Rd b/man/create_random_name.Rd index b27cc387..b2c1a73b 100644 --- a/man/create_random_name.Rd +++ b/man/create_random_name.Rd @@ -44,6 +44,7 @@ Other content functions: \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}()} } diff --git a/man/dashboard_url.Rd b/man/dashboard_url.Rd index dcbccd92..dd768143 100644 --- a/man/dashboard_url.Rd +++ b/man/dashboard_url.Rd @@ -44,6 +44,7 @@ Other content functions: \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}()} } diff --git a/man/dashboard_url_chr.Rd b/man/dashboard_url_chr.Rd index 7a951bce..11b19037 100644 --- a/man/dashboard_url_chr.Rd +++ b/man/dashboard_url_chr.Rd @@ -47,6 +47,7 @@ Other content functions: \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}()} } diff --git a/man/delete_thumbnail.Rd b/man/delete_thumbnail.Rd index 444d8bba..db635a20 100644 --- a/man/delete_thumbnail.Rd +++ b/man/delete_thumbnail.Rd @@ -55,6 +55,7 @@ Other content functions: \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}()} } diff --git a/man/delete_vanity_url.Rd b/man/delete_vanity_url.Rd index 0d43f075..ac440c14 100644 --- a/man/delete_vanity_url.Rd +++ b/man/delete_vanity_url.Rd @@ -10,7 +10,7 @@ delete_vanity_url(content) \item{content}{A Content object} } \description{ -Deletes the Vanity URL for a piece of content. +Delete the vanity URL for a piece of content. } \seealso{ Other content functions: @@ -39,6 +39,7 @@ Other content functions: \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}()} } diff --git a/man/deploy_repo.Rd b/man/deploy_repo.Rd index 1b91da91..018fe807 100644 --- a/man/deploy_repo.Rd +++ b/man/deploy_repo.Rd @@ -82,6 +82,7 @@ Other content functions: \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}()} } diff --git a/man/environment.Rd b/man/environment.Rd index f6d493e5..c183d5e5 100644 --- a/man/environment.Rd +++ b/man/environment.Rd @@ -64,6 +64,7 @@ Other content functions: \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}()} } diff --git a/man/get_bundles.Rd b/man/get_bundles.Rd index 2dbbee8f..47cbb2cf 100644 --- a/man/get_bundles.Rd +++ b/man/get_bundles.Rd @@ -44,6 +44,7 @@ Other content functions: \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}()} @@ -73,6 +74,7 @@ Other content functions: \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}()} } diff --git a/man/get_image.Rd b/man/get_image.Rd index cf270c40..b05e6b42 100644 --- a/man/get_image.Rd +++ b/man/get_image.Rd @@ -54,6 +54,7 @@ Other content functions: \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}()} } diff --git a/man/get_job.Rd b/man/get_job.Rd index 1ae6133c..ad8b7d0a 100644 --- a/man/get_job.Rd +++ b/man/get_job.Rd @@ -48,6 +48,7 @@ Other content functions: \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}()} } diff --git a/man/get_jobs.Rd b/man/get_jobs.Rd index 938b5e3c..2e9d1d30 100644 --- a/man/get_jobs.Rd +++ b/man/get_jobs.Rd @@ -121,6 +121,7 @@ Other content functions: \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}()} } diff --git a/man/get_log.Rd b/man/get_log.Rd index cdb8e3ca..84320076 100644 --- a/man/get_log.Rd +++ b/man/get_log.Rd @@ -70,6 +70,7 @@ Other content functions: \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}()} } diff --git a/man/get_thumbnail.Rd b/man/get_thumbnail.Rd index 2c1bb04d..ad895092 100644 --- a/man/get_thumbnail.Rd +++ b/man/get_thumbnail.Rd @@ -60,6 +60,7 @@ Other content functions: \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}()} } diff --git a/man/get_vanity_url.Rd b/man/get_vanity_url.Rd index 1b25ad40..7ffd1cee 100644 --- a/man/get_vanity_url.Rd +++ b/man/get_vanity_url.Rd @@ -13,7 +13,7 @@ get_vanity_url(content) A character string (or NULL if not defined) } \description{ -Gets the Vanity URL for a piece of content. +Get the vanity URL for a piece of content. } \seealso{ Other content functions: @@ -42,6 +42,7 @@ Other content functions: \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}()} } diff --git a/man/git.Rd b/man/git.Rd index b47ec108..c99786e5 100644 --- a/man/git.Rd +++ b/man/git.Rd @@ -67,6 +67,7 @@ Other content functions: \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}()} } diff --git a/man/has_thumbnail.Rd b/man/has_thumbnail.Rd index cd6cc995..129d7d77 100644 --- a/man/has_thumbnail.Rd +++ b/man/has_thumbnail.Rd @@ -56,6 +56,7 @@ Other content functions: \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}()} } diff --git a/man/permissions.Rd b/man/permissions.Rd index c0de1503..fbbee864 100644 --- a/man/permissions.Rd +++ b/man/permissions.Rd @@ -89,6 +89,7 @@ Other content functions: \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}()} } diff --git a/man/set_image.Rd b/man/set_image.Rd index 8b04cb20..4d9b6709 100644 --- a/man/set_image.Rd +++ b/man/set_image.Rd @@ -60,6 +60,7 @@ Other content functions: \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}()} } diff --git a/man/set_run_as.Rd b/man/set_run_as.Rd index c3b6a70a..40905d18 100644 --- a/man/set_run_as.Rd +++ b/man/set_run_as.Rd @@ -62,6 +62,7 @@ Other content functions: \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}()} } diff --git a/man/set_thumbnail.Rd b/man/set_thumbnail.Rd index d8060ef0..57b441fa 100644 --- a/man/set_thumbnail.Rd +++ b/man/set_thumbnail.Rd @@ -59,6 +59,7 @@ Other content functions: \code{\link{set_run_as}()}, \code{\link{set_vanity_url}()}, \code{\link{swap_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, \code{\link{terminate_jobs}()}, \code{\link{verify_content_name}()} } diff --git a/man/set_vanity_url.Rd b/man/set_vanity_url.Rd index 4b43e264..e65a4265 100644 --- a/man/set_vanity_url.Rd +++ b/man/set_vanity_url.Rd @@ -17,7 +17,7 @@ set_vanity_url(content, url, force = FALSE) An updated Content object } \description{ -Sets the Vanity URL for a piece of content. +Set the vanity URL for a piece of content. } \examples{ \dontrun{ @@ -55,6 +55,7 @@ Other content functions: \code{\link{set_run_as}()}, \code{\link{set_thumbnail}()}, \code{\link{swap_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, \code{\link{terminate_jobs}()}, \code{\link{verify_content_name}()} } diff --git a/man/swap_vanity_url.Rd b/man/swap_vanity_url.Rd index b4c2ea92..1d09db6b 100644 --- a/man/swap_vanity_url.Rd +++ b/man/swap_vanity_url.Rd @@ -2,17 +2,21 @@ % Please edit documentation in R/deploy.R \name{swap_vanity_url} \alias{swap_vanity_url} -\title{Swap the Vanity URL} +\title{Swap Vanity URLs} \usage{ -swap_vanity_url(from_content, to_content) +swap_vanity_url(from, to) } \arguments{ -\item{from_content}{A Content object} +\item{from}{A Content object} -\item{to_content}{A Content object} +\item{to}{A Content object} +} +\value{ +A list of the new vanity URLs for \code{from} and \code{to} } \description{ -Swaps the Vanity URLs between two pieces of content +Swap the vanity URLs of two pieces of content. +This function is deprecated; please use \code{\link{swap_vanity_urls}}. } \seealso{ Other content functions: @@ -41,6 +45,7 @@ Other content functions: \code{\link{set_run_as}()}, \code{\link{set_thumbnail}()}, \code{\link{set_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, \code{\link{terminate_jobs}()}, \code{\link{verify_content_name}()} } diff --git a/man/swap_vanity_urls.Rd b/man/swap_vanity_urls.Rd new file mode 100644 index 00000000..93b78052 --- /dev/null +++ b/man/swap_vanity_urls.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/deploy.R +\name{swap_vanity_urls} +\alias{swap_vanity_urls} +\title{Swap Vanity URLs} +\usage{ +swap_vanity_urls(content_a, content_b) +} +\arguments{ +\item{content_a}{A Content object} + +\item{content_b}{A Content object} +} +\value{ +A list of the new vanity URLs for \code{content_a} and \code{content_b} +} +\description{ +Swap the vanity URLs of two pieces of content. +} +\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{dashboard_url_chr}()}, +\code{\link{delete_thumbnail}()}, +\code{\link{delete_vanity_url}()}, +\code{\link{deploy_repo}()}, +\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_run_as}()}, +\code{\link{set_thumbnail}()}, +\code{\link{set_vanity_url}()}, +\code{\link{swap_vanity_url}()}, +\code{\link{terminate_jobs}()}, +\code{\link{verify_content_name}()} +} +\concept{content functions} diff --git a/man/terminate_jobs.Rd b/man/terminate_jobs.Rd index 0ba9b6fb..6355a96f 100644 --- a/man/terminate_jobs.Rd +++ b/man/terminate_jobs.Rd @@ -73,6 +73,7 @@ Other content functions: \code{\link{set_thumbnail}()}, \code{\link{set_vanity_url}()}, \code{\link{swap_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, \code{\link{verify_content_name}()} } \concept{content functions} diff --git a/man/verify_content_name.Rd b/man/verify_content_name.Rd index 178c1b5c..b9c590e0 100644 --- a/man/verify_content_name.Rd +++ b/man/verify_content_name.Rd @@ -48,6 +48,7 @@ Other content functions: \code{\link{set_thumbnail}()}, \code{\link{set_vanity_url}()}, \code{\link{swap_vanity_url}()}, +\code{\link{swap_vanity_urls}()}, \code{\link{terminate_jobs}()} } \concept{content functions} diff --git a/tests/integrated/test-deploy.R b/tests/integrated/test-deploy.R index 99ceb998..0a6881c2 100644 --- a/tests/integrated/test-deploy.R +++ b/tests/integrated/test-deploy.R @@ -352,42 +352,41 @@ test_that("delete_vanity_url works", { expect_null(res) }) -test_that("swap_vanity_url works", { - tmp_content_name <- uuid::UUIDgenerate() - tmp_content_prep <- content_ensure(test_conn_1, name = tmp_content_name) - tmp_content <- Content$new(connect = test_conn_1, content = tmp_content_prep) +test_that("swap_vanity_urls works", { + tmp_content_a_name <- uuid::UUIDgenerate() + tmp_content_a_prep <- content_ensure(test_conn_1, name = tmp_content_a_name) + tmp_content_a <- Content$new(connect = test_conn_1, content = tmp_content_a_prep) - tmp_content2_name <- uuid::UUIDgenerate() - tmp_content2_prep <- content_ensure(test_conn_1, name = tmp_content2_name) - tmp_content2 <- Content$new(connect = test_conn_1, content = tmp_content2_prep) + tmp_content_b_name <- uuid::UUIDgenerate() + tmp_content_b_prep <- content_ensure(test_conn_1, name = tmp_content_b_name) + tmp_content_b <- Content$new(connect = test_conn_1, content = tmp_content_b_prep) # warns with no vanity urls - res <- suppressMessages(expect_warning(swap_vanity_url(tmp_content, tmp_content2))) - expect_null(res[["from"]]) - expect_null(res[["to"]]) + res <- suppressMessages(expect_warning(swap_vanity_urls(tmp_content_a, tmp_content_b))) + expect_null(res[["content_a"]]) + expect_null(res[["content_b"]]) - # works with just one vanity url (from) - set_from <- set_vanity_url(tmp_content, tmp_content_name) - swap_res <- suppressMessages(swap_vanity_url(tmp_content, tmp_content2)) + # works with just one vanity url (content_a) + set_content_a <- set_vanity_url(tmp_content_a, tmp_content_a_name) + swap_res <- suppressMessages(swap_vanity_urls(tmp_content_a, tmp_content_b)) - expect_identical(swap_res$to, paste0("/", tmp_content_name, "/")) - expect_true(grepl("vanity-url", swap_res$from)) + expect_null(swap_res$content_a) + expect_identical(swap_res$content_b, paste0("/", tmp_content_a_name, "/")) # works with both vanity urls - swap_res2 <- suppressMessages(swap_vanity_url(tmp_content, tmp_content2)) + swap_res2 <- suppressMessages(swap_vanity_urls(tmp_content_a, tmp_content_b)) - expect_identical(swap_res2$from, paste0("/", tmp_content_name, "/")) - expect_identical(swap_res2$to, swap_res$from) + expect_identical(swap_res2$content_a, paste0("/", tmp_content_a_name, "/")) + expect_identical(swap_res2$content_b, swap_res$content_a) - # works with just one vanity url (to) - delete_vanity_url(tmp_content) - expect_null(get_vanity_url(tmp_content)) + # works with just one vanity url (content_b) + delete_vanity_url(tmp_content_a) + expect_null(get_vanity_url(tmp_content_a)) - swap_res3 <- swap_vanity_url(tmp_content, tmp_content2) + swap_res3 <- swap_vanity_urls(tmp_content_a, tmp_content_b) - expect_identical(swap_res3$from, swap_res$from) - expect_false(identical(swap_res3$to, swap_res2$from)) - expect_true(grepl("vanity-url", swap_res3$to)) + expect_identical(swap_res3$content_a, swap_res$content_a) + expect_null(swap_res3$content_b) }) # misc functions --------------------------------------------------- diff --git a/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/README.md b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/README.md new file mode 100644 index 00000000..259c1340 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/README.md @@ -0,0 +1 @@ +This content item allows vanity URL operations. \ No newline at end of file diff --git a/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-795fd3-PUT.json b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-795fd3-PUT.json new file mode 100644 index 00000000..5afc6529 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-795fd3-PUT.json @@ -0,0 +1,5 @@ +{ + "content_guid": "951bf3ad", + "path": "/95/", + "created_time": "2025-01-24T20:53:08Z" +} diff --git a/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-DELETE.204 b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-DELETE.204 new file mode 100644 index 00000000..e69de29b diff --git a/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-babd80-PUT.json b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-babd80-PUT.json new file mode 100644 index 00000000..d2065aba --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity-babd80-PUT.json @@ -0,0 +1,5 @@ +{ + "content_guid": "951bf3ad", + "path": "/new/", + "created_time": "2025-01-06T21:01:45Z" +} diff --git a/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity.json b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity.json new file mode 100644 index 00000000..f8a3eae8 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/951bf3ad/vanity.json @@ -0,0 +1,5 @@ +{ + "content_guid": "951bf3ad", + "path": "/95/", + "created_time": "2025-01-06T21:01:45Z" +} diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b.json b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b.json new file mode 100644 index 00000000..0db47904 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b.json @@ -0,0 +1,49 @@ +// A content item that returns 403 errors when setting and deleting vanity URLs +{ + "guid": "c3426b0b", + "name": "most-used-dashboard-py", + "title": "Vanity URL Swap Test Blue", + "description": "", + "access_type": "acl", + "locked": false, + "locked_message": "", + "extension": false, + "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, + "created_time": "2024-07-12T20:52:06Z", + "last_deployed_time": "2024-07-12T20:52:08Z", + "bundle_id": "124935", + "app_mode": "quarto-static", + "content_category": "", + "parameterized": false, + "cluster_name": null, + "image_name": null, + "r_version": null, + "py_version": null, + "quarto_version": null, + "r_environment_management": null, + "default_r_environment_management": null, + "py_environment_management": null, + "default_py_environment_management": null, + "run_as": null, + "run_as_current_user": false, + "owner_guid": "fe07bf64", + "content_url": "https://connect.example/content/c3426b0b/", + "dashboard_url": "https://connect.example/connect/#/apps/c3426b0b", + "app_role": "viewer", + "id": "51871" +} diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/README.md b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/README.md new file mode 100644 index 00000000..7c6442bb --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/README.md @@ -0,0 +1 @@ +This content item returns 403 errors when setting and deleting vanity URLs. \ No newline at end of file diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-4747c1-PUT.R b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-4747c1-PUT.R new file mode 100644 index 00000000..dc06cca5 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-4747c1-PUT.R @@ -0,0 +1,4 @@ +structure(list( + url = "__api__/v1/content/c3426b0b/vanity", status_code = 403L, + content = charToRaw("{\"code\":22,\"error\":\"You don't have permission to perform this operation.\",\"payload\":null}") +), class = "response") diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-DELETE.R b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-DELETE.R new file mode 100644 index 00000000..dc06cca5 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-DELETE.R @@ -0,0 +1,4 @@ +structure(list( + url = "__api__/v1/content/c3426b0b/vanity", status_code = 403L, + content = charToRaw("{\"code\":22,\"error\":\"You don't have permission to perform this operation.\",\"payload\":null}") +), class = "response") diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-babd80-PUT.R b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-babd80-PUT.R new file mode 100644 index 00000000..dc06cca5 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity-babd80-PUT.R @@ -0,0 +1,4 @@ +structure(list( + url = "__api__/v1/content/c3426b0b/vanity", status_code = 403L, + content = charToRaw("{\"code\":22,\"error\":\"You don't have permission to perform this operation.\",\"payload\":null}") +), class = "response") diff --git a/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity.json b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity.json new file mode 100644 index 00000000..6017f363 --- /dev/null +++ b/tests/testthat/2024.08.0/__api__/v1/content/c3426b0b/vanity.json @@ -0,0 +1,5 @@ +{ + "content_guid": "c3426b0b", + "path": "/c3/", + "created_time": "2025-01-06T21:01:45Z" +} diff --git a/tests/testthat/test-deploy.R b/tests/testthat/test-deploy.R index cda99c87..ff738842 100644 --- a/tests/testthat/test-deploy.R +++ b/tests/testthat/test-deploy.R @@ -65,3 +65,29 @@ test_that("bundle_dir errors for nonexistent paths", { "not TRUE" ) }) + +test_that("swap_vanity_urls() fails gracefully", { + with_mock_api({ + client <- connect(server = "https://connect.example", api_key = "fake") + + works <- content_item(client, "951bf3ad") + fails <- content_item(client, "c3426b0b") + + expect_error( + swap_vanity_urls(fails, works), + paste( + "Unable to modify the vanity URL for content_a:", + "https://connect\\.example/__api__/v1/content/c3426b0b/vanity", + "request failed with Client error: \\(403\\) Forbidden" + ) + ) + expect_error( + swap_vanity_urls(works, fails), + paste( + "Unable to modify the vanity URL for content_b:", + "https://connect\\.example/__api__/v1/content/c3426b0b/vanity", + "request failed with Client error: \\(403\\) Forbidden" + ) + ) + }) +})