Skip to content
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

feat: new function set_content_image(), deprecate old set_image_* functions #303

Merged
merged 37 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3c0f64a
replace and deprecate set_image_* functions
toph-allen Sep 6, 2024
e0ab77a
Merge branch 'main' into toph/simplify_content_image_functions
toph-allen Sep 9, 2024
bc4a58a
first pass at supporting v1 and unversioned urls
toph-allen Sep 9, 2024
72e16b7
second pass at using public URLs
toph-allen Sep 10, 2024
5ec2b31
move all names from _image() to _thumbnail()
toph-allen Sep 11, 2024
a901c71
capture new mocks, move to new dir
toph-allen Sep 12, 2024
4fe07b0
move thumbnail api to its own file
toph-allen Sep 12, 2024
a0e0ec0
working on tests
toph-allen Sep 12, 2024
2c65a63
respond to comments, work on tests
toph-allen Sep 27, 2024
c704809
working on tests
toph-allen Oct 2, 2024
20886af
build out tests
toph-allen Oct 3, 2024
b167c14
update documentation
toph-allen Oct 3, 2024
d9318aa
Reorganize, update deprecated func docs
toph-allen Oct 3, 2024
3a9fa98
minor nits
toph-allen Oct 3, 2024
7c4fbc2
fix and clean up tests
toph-allen Oct 4, 2024
be2951d
specify errors, add new mocks, change error message
toph-allen Oct 4, 2024
a343a75
update README.md
toph-allen Oct 4, 2024
0b83228
add tests of deprecated functions back
toph-allen Oct 4, 2024
7dbdd8a
update NEWS
toph-allen Oct 4, 2024
305252e
remove lingering fs reference
toph-allen Oct 4, 2024
fe66804
respond to comment
toph-allen Oct 4, 2024
362b6a7
clean up mocks
toph-allen Oct 4, 2024
cded553
work on R CMD check
toph-allen Oct 4, 2024
92983be
R CMD check
toph-allen Oct 4, 2024
7be7c34
stray argument
toph-allen Oct 4, 2024
7e1faf2
fix r cmd check
toph-allen Oct 4, 2024
3f1add7
respond to feedback
toph-allen Oct 4, 2024
00f5d4a
work on CI
toph-allen Oct 4, 2024
ed9b73e
integration tests
toph-allen Oct 4, 2024
86bd1f6
Update R/thumbnail.R
toph-allen Oct 7, 2024
67c2960
incorporate review feedback
toph-allen Oct 7, 2024
50989c7
revert some changes to integration tests
toph-allen Oct 7, 2024
aa0063c
respond to feedback and fix integration tests
toph-allen Oct 7, 2024
bf76311
update tested versions & news
toph-allen Oct 7, 2024
5ce4f4a
roll back change to integration tests
toph-allen Oct 7, 2024
7a21907
clarify relationship between server_url and api_url
toph-allen Oct 8, 2024
7308420
Restore 1.8.8.2 integration tests
toph-allen Oct 8, 2024
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 @@ -32,6 +32,7 @@ Imports:
fs,
glue,
httr,
mime,
jsonlite,
lifecycle,
magrittr,
Expand Down
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export(dashboard_url_chr)
export(delete_bundle)
export(delete_image)
export(delete_tag)
export(delete_thumbnail)
export(delete_vanity_url)
export(deploy)
export(deploy_current)
Expand All @@ -84,6 +85,7 @@ export(get_oauth_credentials)
export(get_procs)
export(get_tag_data)
export(get_tags)
export(get_thumbnail)
export(get_timezones)
export(get_usage_shiny)
export(get_usage_static)
Expand All @@ -97,6 +99,7 @@ export(get_variant_schedule)
export(get_variants)
export(groups_create_remote)
export(has_image)
export(has_thumbnail)
export(page_cursor)
export(page_offset)
export(poll_task)
Expand Down Expand Up @@ -127,6 +130,7 @@ export(set_schedule_semimonth)
export(set_schedule_week)
export(set_schedule_weekday)
export(set_schedule_year)
export(set_thumbnail)
export(set_vanity_url)
export(swap_vanity_url)
export(tbl_connect)
Expand Down
18 changes: 18 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# Unreleased

## New features

- New functions `set_thumbnail()`, `get_thumbnail()`, `delete_thumbnail()` and
`has_thumbnail()` let you interact with content thumbnails, replacing older
`*_image()` functions.

## Lifecycle changes

### Newly deprecated

- `set_image_path()`, `set_image_url()`, and `set_image_webshot()` have been
deprecated and will be removed in a future update. They have been replaced by
`set_thumbnail()`, which works both with local file paths and remote URLs to
images. Likewise, `has_image()` and `delete_image()` have been deprecated in
favor of `has_thumbnail()` and `delete_thumbnail()`.

# connectapi 0.3.0

## Breaking changes
Expand Down
8 changes: 7 additions & 1 deletion R/connect.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#' @family R6 classes
#'
#' @export
Connect <- R6::R6Class(

Check warning on line 23 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=23,col=1,[cyclocomp_linter] Functions should have cyclomatic complexity of less than 15, this has 26.

Check warning on line 23 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=23,col=1,[object_name_linter] Variable and function name style should match snake_case or symbols.
"Connect",
public = list(
#' @field server The base URL of your Posit Connect server.
Expand Down Expand Up @@ -67,7 +67,7 @@
print = function(...) {
cat("Posit Connect API Client: \n")
cat(" Posit Connect Server: ", self$server, "\n", sep = "")
cat(" Posit Connect API Key: ", paste0(strrep("*", 11), substr(self$api_key, nchar(self$api_key) - 3, nchar(self$api_key))), "\n", sep = "")

Check warning on line 70 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=70,col=101,[line_length_linter] Lines should not be more than 100 characters. This line is 147 characters.
# TODO: something about API key... role... ?
# TODO: point to docs on methods... how to see methods?
cat("\n")
Expand Down Expand Up @@ -107,7 +107,13 @@
#' @description Build a URL relative to the API root
#' @param ... path segments
api_url = function(...) {
paste(self$server, "__api__", ..., sep = "/")
self$server_url("__api__", ...)
},

#' @description Build a URL relative to the server root
#' @param ... path segments
server_url = function(...) {
paste(self$server, ..., sep = "/")
},

#' @description General wrapper around `httr` verbs
Expand Down Expand Up @@ -181,7 +187,7 @@
self$request("HEAD", url, parser = NULL, ...)
},

#' @description Perform an HTTP DELETE request of the named API path. Returns the HTTP response object.

Check warning on line 190 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=190,col=101,[line_length_linter] Lines should not be more than 100 characters. This line is 107 characters.
#' @param path API path relative to the server's `/__api__` root.
#' @param ... Arguments to `httr::DELETE()`
#' @param url Target URL. Default uses `path`, but provide `url` to request
Expand Down Expand Up @@ -352,7 +358,7 @@
count = min(page_size, .limit)
)
if (!is.null(filter)) {
query$filter <- paste(sapply(1:length(filter), function(i) {

Check warning on line 361 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=361,col=38,[seq_linter] 1:length(...) is likely to be wrong in the empty edge case. Use seq_along(...) instead.
sprintf("%s:%s", names(filter)[i], filter[[i]])
}), collapse = .collapse)
}
Expand Down Expand Up @@ -745,7 +751,7 @@
warn_experimental("repo_account")
parsed_url <- httr::parse_url(host)
if (is.null(parsed_url$scheme) || is.null(parsed_url$hostname)) {
stop(glue::glue("Scheme and hostname must be provided (i.e. 'https://github.com'). You provided '{host}'"))

Check warning on line 754 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=754,col=101,[line_length_linter] Lines should not be more than 100 characters. This line is 115 characters.
}
host <- glue::glue(parsed_url$scheme, "://", parsed_url$hostname)
path <- unversioned_url("repo", "account")
Expand Down Expand Up @@ -775,7 +781,7 @@
#' @param start Starting time.
#' @param end Ending time.
#' @param detailed Indicates detailed schedule information.
schedules = function(start = Sys.time(), end = Sys.time() + 60 * 60 * 24 * 7, detailed = FALSE) {

Check warning on line 784 in R/connect.R

View workflow job for this annotation

GitHub Actions / lint

file=R/connect.R,line=784,col=101,[line_length_linter] Lines should not be more than 100 characters. This line is 101 characters.
warn_experimental("schedules")
url <- v1_url("experimental", "schedules")
query_params <- rlang::list2(
Expand Down
166 changes: 0 additions & 166 deletions R/deploy.R
Original file line number Diff line number Diff line change
Expand Up @@ -399,172 +399,6 @@ deploy_current <- function(content) {
return(ContentTask$new(connect = content$get_connect(), content = content, task = res))
}


#' Get the Content Image
#'
#' \lifecycle{experimental}
#' `get_image` saves the content image to the given path (default: temp file).
#' `delete_image` removes the image (optionally saving to the given path)
#' `has_image` returns whether the content has an image
#'
#' @param content A content object
#' @param path optional. The path to the image on disk
#'
#' @rdname get_image
#' @family content functions
#' @export
get_image <- function(content, path = NULL) {
warn_experimental("get_image")
validate_R6_class(content, "Content")
guid <- content$get_content()$guid

con <- content$get_connect()

res <- con$GET(
unversioned_url("applications", guid, "image"),
parser = NULL
)

if (httr::status_code(res) == 204) {
return(NA)
}

# guess file extension
if (is.null(path)) {
ct <- httr::headers(res)$`content-type`
if (grepl("^image/", ct)) {
# just strip off 'image/'
ext <- substr(ct, 7, nchar(ct))
path <- fs::file_temp(pattern = "content_image_", ext = ext)
} else {
# try png
warning(glue::glue("Could not infer file extension from content type: {ct}. Using '.png'"))
path <- fs::file_temp(pattern = "content_image_", ext = ".png")
}
}

writeBin(httr::content(res, as = "raw"), path)

return(fs::as_fs_path(path))
}

#' @rdname get_image
#' @export
delete_image <- function(content, path = NULL) {
warn_experimental("delete_image")
validate_R6_class(content, "Content")
guid <- content$get_content()$guid

con <- content$get_connect()

if (!is.null(path)) {
scoped_experimental_silence()
get_image(content, path)
}

res <- con$DELETE(unversioned_url("applications", guid, "image"))

return(content)
}

#' @rdname get_image
#' @export
has_image <- function(content) {
warn_experimental("has_image")
validate_R6_class(content, "Content")
guid <- content$get_content()$guid

con <- content$get_connect()

res <- con$GET(unversioned_url("applications", guid, "image"), parser = NULL)

httr::status_code(res) != 204
}

#' Set the Content Image
#'
#' \lifecycle{experimental}
#'
#' Set the Content Image using a variety of methods.
#'
#' NOTE: `set_image_webshot()` requires [webshot2::webshot()], but currently
#' skips and warns for any content that requires authentication until the
#' `webshot2` package supports authentication.
#'
#' @param content A content object
#' @param path The path to an image on disk
#' @param url The url for an image
#' @param ... Additional arguments passed on to [webshot2::webshot()]
#'
#' @rdname set_image
#' @family content functions
#' @export
set_image_path <- function(content, path) {
warn_experimental("set_image_path")
validate_R6_class(content, "Content")
guid <- content$get_content()$guid

con <- content$get_connect()

res <- con$POST(
path = unversioned_url("applications", guid, "image"),
body = httr::upload_file(path)
)

# return the input (in case it inherits more than just Content)
content
}

#' @rdname set_image
#' @export
set_image_url <- function(content, url) {
warn_experimental("set_image_url")
validate_R6_class(content, "Content")
parsed_url <- httr::parse_url(url)
imgfile <- fs::file_temp(pattern = "image", ext = fs::path_ext(parsed_url[["path"]]))
httr::GET(url, httr::write_disk(imgfile))

set_image_path(content = content, path = imgfile)
}

#' @rdname set_image
#' @export
set_image_webshot <- function(content, ...) {
warn_experimental("set_image_webshot")
validate_R6_class(content, "Content")
imgfile <- fs::file_temp(pattern = "webshot", ext = ".png")

rlang::check_installed("webshot2", "to take screenshots of applications")
content_details <- content$get_content_remote()

# check if it is possible to take the webshot
if (content_details$access_type != "all") {
warning(glue::glue(
"WARNING: unable to take webshot for content ",
"'{content_details$guid}' because authentication is not possible yet. ",
"Set access_type='all' to proceed."
))
return(content)
}

# default args
args <- rlang::list2(...)

if (!"cliprect" %in% names(args)) {
args["cliprect"] <- "viewport"
}


rlang::inject(webshot2::webshot(
url = content_details$content_url,
file = imgfile,
!!!args
))

set_image_path(content = content, path = imgfile)
}


#' Set the Vanity URL
#'
#' Sets the Vanity URL for a piece of content.
Expand Down
Loading
Loading