Skip to content

Commit cd8291a

Browse files
jonkeanetoph-allennealrichardsonschloerke
authored
Allow exact group matches (#261)
Co-authored-by: Toph Allen <[email protected]> Co-authored-by: Neal Richardson <[email protected]> Co-authored-by: Barret Schloerke <[email protected]>
1 parent cf2b801 commit cd8291a

15 files changed

+416
-43
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ connectapi*.tgz
1414
*.orig
1515
tests/integrated/integrated-results-check.txt
1616
tests/integrated/testthat-problems.rds
17-
CRAN-SUBMISSION
17+
CRAN-SUBMISSION
18+
tests/testthat/Rplots.pdf

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
- New functions `set_thumbnail()`, `get_thumbnail()`, `delete_thumbnail()` and
88
`has_thumbnail()` let you interact with content thumbnails, replacing older
99
`*_image()` functions. (#294, #304)
10+
- `groups_create_remote()` now has an `exact` parameter. Setting `exact` causes
11+
the function to consider only exact group name matches when searching for
12+
remote groups and checking for existing local groups. (#216)
1013

1114
## Lifecycle changes
1215

R/get.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ get_users <- function(src, page_size = 500, prefix = NULL, limit = Inf) {
5959
#' @param page_size the number of records to return per page (max 500)
6060
#' @param prefix Filters groups by prefix (group name).
6161
#' The filter is case insensitive.
62-
#' @param limit The max number of groups to return
62+
#' @param limit The max number of groups to return.
6363
#'
6464
#' @return
6565
#' A tibble with the following columns:

R/remote.R

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
#' NOTE: there can be problems with usernames that are not unique. Please open
1010
#' an issue if you run into any problems.
1111
#'
12-
#' @param connect A R6 Connect object
13-
#' @param prefix character. The prefix of the user name to search for
14-
#' @param expect number. Optional. The number of responses to expect for this search
15-
#' @param check boolean. Optional. Whether to check for local existence first
12+
#' @param connect An R6 Connect object.
13+
#' @param prefix character. The prefix of the user name to search for.
14+
#' @param expect number. Optional. The number of responses to expect for this search.
15+
#' @param check boolean. Optional. Whether to check for local existence first.
1616
#' @param exact boolean. Optional. Whether to only create users whose username
1717
#' exactly matches the provided `prefix`.
1818
#'
19-
#' @return The results of creating the users
19+
#' @return The results of creating the users.
2020
#'
2121
#' @export
2222
users_create_remote <- function(connect, prefix, expect = 1, check = TRUE, exact = FALSE) {
@@ -63,39 +63,50 @@ users_create_remote <- function(connect, prefix, expect = 1, check = TRUE, exact
6363

6464
#' Create a Remote Group
6565
#'
66-
#' @param connect A R6 Connect object
67-
#' @param prefix character. The prefix of the group name to search for
68-
#' @param expect number. The number of responses to expect for this search
69-
#' @param check boolean. Whether to check for local existence first
66+
#' @param connect An R6 Connect object.
67+
#' @param prefix character. The prefix of the user name to search for.
68+
#' @param expect number. Optional. The number of responses to expect for this search.
69+
#' @param check boolean. Optional. Whether to check for local existence first.
70+
#' @param exact boolean. Optional. Whether to only create groups whose name
71+
#' exactly matches the provided `prefix`.
7072
#'
71-
#' @return The results of creating the groups
73+
#' @return The results of creating the groups.
7274
#'
7375
#' @export
74-
groups_create_remote <- function(connect, prefix, expect = 1, check = TRUE) {
76+
groups_create_remote <- function(connect, prefix, expect = 1, check = TRUE, exact = FALSE) {
7577
expect <- as.integer(expect)
76-
if (check && expect > 1) {
77-
stop(glue::glue("expect > 1 is not tested. Please set expect = 1, and specify a more narrow 'prefix'. You provided: expect={expect}"))
78-
}
7978
if (check) {
8079
# TODO: limit = 1 due to a paging bug in Posit Connect
81-
local_groups <- get_groups(connect, prefix = prefix, limit = 1)
80+
local_groups <- get_groups(connect, page_size = 500, prefix = prefix, limit = 1)
81+
if (exact) {
82+
local_groups <- local_groups[local_groups["name"] == prefix, ]
83+
}
8284
if (nrow(local_groups) > 0) {
83-
message(glue::glue("At least one group with name prefix '{prefix}' already exists"))
85+
if (!exact) {
86+
message(glue::glue("At least one group with name prefix '{prefix}' already exists"))
87+
} else {
88+
message(glue::glue("A group with the name '{prefix}' already exists"))
89+
90+
}
8491
return(local_groups)
8592
}
8693
}
8794

8895
remote_groups <- connect$groups_remote(prefix = prefix)
89-
if (remote_groups$total != expect) {
90-
message(glue::glue("Found {remote_groups$total} remote groups. Expected {expect}"))
91-
if (remote_groups$total > 0) {
92-
group_str <- toString(purrr::map_chr(remote_groups$results, ~ .x[["name"]]))
93-
message(glue::glue("Groups found: {group_str}"))
96+
remote_groups_res <- remote_groups[["results"]]
97+
if (exact) {
98+
remote_groups_res <- purrr::keep(remote_groups_res, ~ .x[["name"]] == prefix)
99+
}
100+
if (length(remote_groups_res) != expect) {
101+
message(glue::glue("Found {length(remote_groups_res)} remote groups. Expected {expect}"))
102+
if (length(remote_groups_res) > 0) {
103+
groups_found <- glue::glue_collapse(purrr::map_chr(remote_groups_res, ~ .x[["name"]]), sep = ", ")
104+
message(glue::glue("Groups found: {groups_found}"))
94105
}
95106
stop("The expected group(s) were not found. Please specify a more accurate 'prefix'")
96107
}
97108
group_creation <- purrr::map(
98-
remote_groups$results,
109+
remote_groups_res,
99110
function(.x, src) {
100111
message(glue::glue("Creating remote group: {.x[['name']]}"))
101112
src$groups_create_remote(temp_ticket = .x[["temp_ticket"]])

man/get_groups.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/groups_create_remote.Rd

Lines changed: 9 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/users_create_remote.Rd

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"results": [
3+
{
4+
"name": "Everyone Else"
5+
}
6+
],
7+
"current_page": 1,
8+
"total": 1
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// v1/groups?page_number=1&page_size=500&prefix=Art
2+
{
3+
"results": [
4+
],
5+
"current_page": 1,
6+
"total": 0
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"results": [
3+
],
4+
"current_page": 1,
5+
"total": 0
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// v1/groups {"temp_ticket":"fake-art"}
2+
{
3+
"guid": "1c1ab604-4a6a-4d07-9477-a88ac08386cd",
4+
"name": "Art",
5+
"owner_guid": null
6+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// v1/groups/remote?limit=500&prefix=Art
2+
{
3+
"results": [
4+
{
5+
"name": "Art",
6+
"guid": null,
7+
"temp_ticket": "fake-art"
8+
},
9+
{
10+
"name": "Arthur O Eve - E O P Program",
11+
"guid": null,
12+
"temp_ticket": "fake-arthur"
13+
}
14+
],
15+
"current_page": 1,
16+
"total": 2
17+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"results": [
3+
],
4+
"current_page": 1,
5+
"total": 1
6+
}

tests/testthat/setup.R

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,23 @@ MockConnect <- R6Class(
4646
self$api_key <- "fake"
4747
private$.version <- version
4848
},
49+
# The request function matches the route against the routes in the names of
50+
# the response list. When a response is selected, it is removed from the
51+
# list.
4952
request = function(method, url, ..., parser = "parsed") {
5053
route <- paste(method, url)
51-
print(route)
5254

5355
# Record call
5456
self$log_call(route)
5557

5658
# Look for response
5759
if (!(route %in% names(self$responses))) {
58-
stop("Unexpected route")
60+
stop(glue::glue("Unexpected route: {route}"))
5961
}
60-
res <- self$responses[[route]]
62+
63+
idx <- match(route, names(self$responses))
64+
res <- self$responses[[idx]]
65+
self$responses <- self$responses[-idx]
6166

6267
if (is.null(parser)) {
6368
res
@@ -67,12 +72,22 @@ MockConnect <- R6Class(
6772
}
6873
},
6974
responses = list(),
75+
# Add a response to a list of responses. The response is keyed according to
76+
# its route, represented as `{VERB} {URL}`. The URL is constructed as an API
77+
# URL for the server (this will probably have to change in the future). Each
78+
# response can only be used once. You can supply multiple responses for the
79+
# same URL.
7080
mock_response = function(method, path, content, status_code = 200L, headers = c("Content-Type" = "application/json; charset=utf-8")) {
7181
url <- self$api_url(path)
72-
route <- paste(method, url)
73-
print(route)
82+
7483
res <- new_mock_response(url, content, status_code, headers)
75-
self$responses[[route]] <- res
84+
85+
route <- paste(method, url)
86+
new_response <- list(res)
87+
new_response <- setNames(new_response, route)
88+
89+
self$responses <- append(self$responses, new_response)
90+
7691
},
7792
call_log = character(),
7893
log_call = function(route) {
@@ -91,7 +106,7 @@ new_mock_response <- function(url, content, status_code, headers = character())
91106
if (is.character(content) && length(content) == 1) {
92107
content <- charToRaw(content)
93108
} else if (is.list(content)) {
94-
content <- charToRaw(jsonlite::toJSON(content, auto_unbox = TRUE))
109+
content <- charToRaw(jsonlite::toJSON(content, auto_unbox = TRUE, null = "null"))
95110
}
96111

97112
structure(

0 commit comments

Comments
 (0)