Skip to content

Commit ef69b95

Browse files
authored
Merge pull request #62 from elipousson/feat-as_arc_url
Add URL conversion functions
2 parents ac8c8d1 + 2dd5f8d commit ef69b95

25 files changed

+799
-111
lines changed

DESCRIPTION

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ Imports:
3232
RcppSimdJson,
3333
rlang,
3434
sf,
35-
utils
35+
utils,
36+
lifecycle
3637
Suggests:
3738
arcgisbinding,
3839
collapse (>= 2.0.0),
3940
data.table,
4041
jsonify,
4142
testthat (>= 3.0.0),
43+
curl,
4244
vctrs
4345
Config/rextendr/version: 0.3.1.9001
4446
Config/testthat/edition: 3

NAMESPACE

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ S3method(has_m,sfc)
66
S3method(has_m,sfg)
77
S3method(has_z,sfc)
88
S3method(has_z,sfg)
9+
S3method(print,PortalItem)
910
export("%||%")
1011
export(arc_agent)
1112
export(arc_base_req)
13+
export(arc_group)
1214
export(arc_host)
15+
export(arc_item)
16+
export(arc_item_data)
17+
export(arc_portal_urls)
1318
export(arc_self_meta)
1419
export(arc_token)
1520
export(arc_url_parse)
21+
export(arc_url_type)
22+
export(arc_user)
1623
export(as_esri_features)
1724
export(as_esri_featureset)
1825
export(as_esri_geometry)
@@ -42,6 +49,7 @@ export(has_m)
4249
export(has_z)
4350
export(infer_esri_type)
4451
export(is_date)
52+
export(is_url)
4553
export(obj_check_token)
4654
export(parse_esri_json)
4755
export(ptype_tbl)
@@ -52,4 +60,5 @@ export(set_arc_token)
5260
export(unset_arc_token)
5361
export(validate_crs)
5462
export(validate_or_refresh_token)
63+
importFrom(lifecycle,deprecated)
5564
useDynLib(arcgisutils, .registration = TRUE)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# arcgisutils (development version)
22

3+
- Adds new experimental functions for parsing urls `arc_url_parse()`, `arc_url_type()`, and `is_url()` h/t [@elipousson](https://github.com/elipousson)
4+
- Adds new experimental functions for working with a portal's sharing API `arc_item()`, `arc_group()`, `arc_user()`, `arc_item_data()`, `arc_portal_urls()`
35
- Validate `token` in `arc_base_req()`
46

57
# arcgisutils 0.3.2

R/arc-auth.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,17 @@ validate_or_refresh_token <- function(
285285
) {
286286
# validate the object is a token
287287
obj_check_token(token, call = call)
288-
check_string(client, allow_empty = FALSE)
288+
check_string(client, allow_empty = TRUE)
289289
check_string(host, allow_empty = FALSE)
290290
check_number_whole(refresh_threshold, min = 0, max = 3600)
291291

292292
cur_time <- as.numeric(Sys.time())
293293

294+
# if there isn't a client token value then we can return the token
295+
if (!nzchar(client)) {
296+
return(token)
297+
}
298+
294299
# provide an error if there is an expired token
295300
if (token[["expires_at"]] <= cur_time) {
296301
cli::cli_abort("Provided token has expired", call = call)

R/arc-base-req.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ arc_base_req <- function(
5656
# if token is not missing, check it
5757
if (!is.null(token)) {
5858
# ensure that the token is an httr2_token
59-
token <- validate_or_refresh_token(token, error_call)
59+
# token <- validate_or_refresh_token(token, error_call)
6060

6161
# set the auth header
6262
req <- httr2::req_headers(

R/arcgisutils-package.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## usethis namespace: start
2-
#' @useDynLib arcgisutils, .registration = TRUE
2+
#' @importFrom lifecycle deprecated
33
#' @keywords internal
4+
#' @useDynLib arcgisutils, .registration = TRUE
45
## usethis namespace: end
56
NULL

R/sharing.R

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#' Portal Item Metadata
2+
#'
3+
#' Given the unique ID of a content item, fetches the item's metadata from a portal.
4+
#'
5+
#' @param item_id the ID of the item to fetch. A scalar character.
6+
#' @inheritParams auth_user
7+
#' @details
8+
#'
9+
#' See [API Reference](https://developers.arcgis.com/rest/users-groups-and-items/item/) for more information.
10+
#'
11+
#' `r lifecycle::badge("experimental")`
12+
#' @export
13+
#' @family portal item
14+
#' @examplesIf curl::has_internet()
15+
#' arc_item("9df5e769bfe8412b8de36a2e618c7672")
16+
#' @returns an object of class `PortalItem` which is a list with the item's metadata.
17+
arc_item <- function(item_id, host = arc_host(), token = arc_token()) {
18+
check_string(item_id, allow_empty = FALSE)
19+
resp <- arc_base_req(
20+
host,
21+
path = paste0("sharing/rest/content/items/", item_id),
22+
token,
23+
query = c("f" = "json")
24+
) |>
25+
httr2::req_perform() |>
26+
httr2::resp_body_string() |>
27+
RcppSimdJson::fparse() |>
28+
detect_errors()
29+
30+
structure(resp, class = c("PortalItem", "list"))
31+
}
32+
33+
#' @export
34+
print.PortalItem <- function(x, ...) {
35+
cat(sprintf("<PortalItem<%s>>\n", x$type))
36+
for (field in c("id", "title", "owner")) {
37+
cat(field, ": ", x[[field]], "\n", sep = "")
38+
}
39+
invisible(x)
40+
}
41+
42+
#' Organization's URLs
43+
#'
44+
#' Returns the URLs of an organizations services.
45+
#'
46+
#' See [API Reference](https://developers.arcgis.com/rest/users-groups-and-items/urls/) for more information.
47+
#' `r lifecycle::badge("experimental")`
48+
#' @export
49+
#' @family portal
50+
#' @inheritParams auth_user
51+
#' @examplesIf curl::has_internet()
52+
#' arc_portal_urls()
53+
arc_portal_urls <- function(host = arc_host(), token = arc_token()) {
54+
arc_base_req(
55+
host,
56+
token,
57+
"sharing/rest/portals/self/urls",
58+
query = c("f" = "json")
59+
) |>
60+
httr2::req_perform() |>
61+
httr2::resp_body_string() |>
62+
RcppSimdJson::fparse()
63+
}
64+
65+
66+
#' Download an Item's Data
67+
#'
68+
#' Download the data backing a portal item. This function always returns
69+
#' a raw vector as the type of the data that is downloaded cannot always be known.
70+
#'
71+
#' `r lifecycle::badge("experimental")`
72+
#' @param item the item ID or the result of `arc_item()`.
73+
#' @export
74+
#' @inheritParams auth_user
75+
#' @family portal item
76+
#' @examplesIf curl::has_internet()
77+
#' arc_item_data("9df5e769bfe8412b8de36a2e618c7672")
78+
#' @returns a raw vector containing the bytes of the data associated with the item. If the response is `application/json` then the json string is returned without parsing.
79+
arc_item_data <- function(
80+
item,
81+
host = arc_host(),
82+
token = arc_token()
83+
) {
84+
e_msg <- "Expected a content ID or {.cls PortalItem<_>} created with {.fn arc_item}"
85+
86+
if (rlang::is_string(item)) {
87+
item <- rlang::try_fetch(
88+
arc_item(item, host, token),
89+
error = function(cnd) cli::cli_abort(e_msg)
90+
)
91+
}
92+
93+
if (!inherits(item, "PortalItem")) {
94+
cli::cli_abort(e_msg)
95+
}
96+
97+
resp <- arc_base_req(
98+
host,
99+
path = c("sharing/rest/content/items/", item[["id"]], "data"),
100+
token
101+
) |>
102+
httr2::req_perform()
103+
104+
resp_type <- httr2::resp_content_type(resp)
105+
106+
if (resp_type == "application/json") {
107+
resp_str <- httr2::resp_body_string(resp)
108+
catch_error(resp_str)
109+
resp_str
110+
} else {
111+
httr2::resp_body_raw(resp)
112+
}
113+
}
114+
115+
116+
#' Fetch Group Information
117+
#'
118+
#' Fetches metadata about a group based on a provided `group_id`.
119+
#'
120+
#' `r lifecycle::badge("experimental")`
121+
#' @param group_id the unique group identifier. A scalar character.
122+
#' @inheritParams arc_item
123+
#' @export
124+
#' @family portal organization
125+
#' @examplesIf curl::has_internet()
126+
#' arc_group("2f0ec8cb03574128bd673cefab106f39")
127+
#' @returns a list with group metadata
128+
arc_group <- function(
129+
group_id,
130+
host = arc_host(),
131+
token = arc_token()
132+
) {
133+
check_string(group_id)
134+
arc_base_req(
135+
host,
136+
token,
137+
c("sharing/rest/community/groups", group_id),
138+
query = c("f" = "json")
139+
) |>
140+
httr2::req_perform() |>
141+
httr2::resp_body_string() |>
142+
RcppSimdJson::fparse() |>
143+
detect_errors()
144+
}
145+
146+
#' User Information
147+
#'
148+
#' Fetch a user's metadata based on username.
149+
#'
150+
#' `r lifecycle::badge("experimental")`
151+
#'
152+
#' @param username the username to fetch. A scalar character.
153+
#' @inheritParams arc_item
154+
#' @export
155+
#' @family portal organization
156+
#' @examplesIf curl::has_internet()
157+
#' arc_user("esri_en")
158+
arc_user <- function(username, host = arc_host(), token = arc_token()) {
159+
arc_base_req(
160+
host,
161+
token,
162+
c("sharing/rest/community/users", username),
163+
query = c("f" = "json")
164+
) |>
165+
httr2::req_perform() |>
166+
httr2::resp_body_string() |>
167+
RcppSimdJson::fparse() |>
168+
detect_errors()
169+
}

R/utils-requests.R

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
#' meta <- fetch_layer_metadata(furl)
2323
#' head(names(meta))
2424
#' @returns returns a list object
25-
fetch_layer_metadata <- function(url, token = NULL, call = rlang::caller_env()) {
25+
fetch_layer_metadata <- function(
26+
url,
27+
token = NULL,
28+
call = rlang::caller_env()
29+
) {
2630
req <- arc_base_req(url, token, error_call = call)
2731

2832
# add f=json to the url for querying
@@ -75,7 +79,7 @@ detect_errors <- function(response, error_call = rlang::caller_env()) {
7579
e_msg <- capture_message(response)
7680

7781
if (is.null(e_msg)) {
78-
return(invisible(NULL))
82+
return(response)
7983
}
8084

8185
rlang::abort(

0 commit comments

Comments
 (0)