Skip to content
2 changes: 1 addition & 1 deletion .lintr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
linters: linters_with_defaults(line_length_linter = line_length_linter(120))
exclusions: list("_wip", "tests/testthat", "vignettes", "R/CONSTANTS.R" = list(object_name_linter = Inf), "R/aaa.R" = list(object_name_linter = Inf), "R/auth_utils.R" = list(object_name_linter = Inf), "R/utils.R" = list(object_name_linter = Inf))
exclusions: list("_wip", "tests/testthat", "vignettes", "R/CONSTANTS.R" = list(object_name_linter = Inf, object_length_linter = Inf), "R/aaa.R" = list(object_name_linter = Inf), "R/auth_utils.R" = list(object_name_linter = Inf), "R/utils.R" = list(object_name_linter = Inf))
7 changes: 7 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

export("%>%")
export(HHMMSSmmm_to_ms)
export(add_default_record_to_session)
export(assign_constants)
export(assign_record_to_file)
export(check_duplicate_files_in_session)
export(check_ssl_certs)
export(create_session)
export(create_volume_record)
export(delete_record_measure)
export(delete_session)
export(delete_volume_record)
export(disable_volume_category)
export(download_folder_asset)
Expand Down Expand Up @@ -72,6 +76,8 @@ export(login_db)
export(logout_db)
export(make_default_request)
export(make_login_client)
export(patch_session)
export(remove_default_record_from_session)
export(search_for_funder)
export(search_for_tags)
export(search_institutions)
Expand All @@ -80,6 +86,7 @@ export(search_volumes)
export(set_record_measure)
export(set_volume_enabled_categories)
export(unassign_record_from_file)
export(update_session)
export(update_volume_record)
export(whoami)
importFrom(lifecycle,deprecated)
Expand Down
3 changes: 3 additions & 0 deletions R/CONSTANTS.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ API_VOLUME_RECORDS <- "/volumes/%s/records/"
API_VOLUME_RECORD_DETAIL <- "/volumes/%s/records/%s/"
API_RECORD_MEASURES <- "/volumes/%s/records/%s/measures/%s/"
API_SESSION_DETAIL <- "/volumes/%s/sessions/%s/"
API_SESSION_ADD_DEFAULT_RECORD <- "/volumes/%s/sessions/%s/add-default-record/"
API_SESSION_REMOVE_DEFAULT_RECORD <- "/volumes/%s/sessions/%s/remove-default-record/"
API_SESSION_CHECK_DUPLICATE_FILES <- "/volumes/%s/sessions/%s/check-duplicate-files/"
API_SESSION_FILES <- "/volumes/%s/sessions/%s/files/"
API_SESSION_FILE_DETAIL <- "/volumes/%s/sessions/%s/files/%s/"
API_SESSION_FILE_ASSIGN <- "/volumes/%s/sessions/%s/files/%s/assign-record/"
Expand Down
63 changes: 63 additions & 0 deletions R/add_default_record_to_session.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#' @eval options::as_params()
#' @name options_params
#'
NULL

#' Add a Default Record to a Session
#'
#' @description Attach a record to a session as a default record. Default
#' records apply to all files in the session unless overridden. The record
#' must either belong to the destination volume or be accessible to it via a
#' linked volume; the server enforces this and returns \code{403} otherwise.
#'
#' @param vol_id Target volume number. Must be a positive integer.
#' @param session_id Numeric session identifier. Must be a positive integer.
#' @param record_id Numeric record identifier. Must be a positive integer.
#' @param rq An \code{httr2} request object. Defaults to \code{NULL}.
#'
#' @return \code{TRUE} if the record was successfully added, \code{FALSE}
#' otherwise.
#'
#' @seealso \code{\link{remove_default_record_from_session}}
#'
#' @inheritParams options_params
#'
#' @examples
#' \donttest{
#' \dontrun{
#' add_default_record_to_session(vol_id = 1, session_id = 42, record_id = 101)
#' }
#' }
#' @export
add_default_record_to_session <- function(
vol_id = 1,
session_id,
record_id,
vb = options::opt("vb"),
rq = NULL
) {
assert_positive_integer(vol_id, "vol_id")
assert_positive_integer(session_id, "session_id")
assert_positive_integer(record_id, "record_id")
assertthat::assert_that(is.logical(vb), length(vb) == 1)
assertthat::assert_that(is.null(rq) || inherits(rq, "httr2_request"))

result <- perform_api_post(
path = sprintf(API_SESSION_ADD_DEFAULT_RECORD, vol_id, session_id),
body = list(record_id = record_id),
rq = rq,
vb = vb
)

if (is.null(result)) {
if (vb) {
message(
"Failed to add default record ", record_id,
" to session ", session_id, " in volume ", vol_id
)
}
return(FALSE)
}

TRUE
}
47 changes: 47 additions & 0 deletions R/api_utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,53 @@ perform_api_patch <- function(path,
payload
}

#' @noRd
# TODO: verify behavior against the live API. Mirrors `perform_api_patch`,
# but no existing wrapper currently issues PUT, so this helper is unexercised.
perform_api_put <- function(path,
body = list(),
rq = NULL,
vb = FALSE,
normalize = TRUE) {
request <- rq
if (is.null(request)) {
request <- databraryr::make_default_request()
}

url <- paste0(DATABRARY_BASE_URL, ensure_leading_slash(path))
request <- httr2::req_url(request, url)
request <- httr2::req_method(request, "PUT")

if (!is.null(body) && length(body) > 0) {
request <- httr2::req_body_json(request, body)
}

response <- tryCatch(
httr2::req_perform(request),
httr2_error = function(cnd) {
if (vb) {
message("PUT request failed for ", url, ": ", conditionMessage(cnd))
}
NULL
}
)

if (is.null(response)) {
return(NULL)
}

status <- httr2::resp_status(response)
if (status == 204L || !resp_has_body(response)) {
return(TRUE)
}

payload <- httr2::resp_body_json(response)
if (isTRUE(normalize)) {
payload <- snake_case_list(payload)
}
payload
}

#' @noRd
perform_api_delete <- function(path,
rq = NULL,
Expand Down
85 changes: 85 additions & 0 deletions R/check_duplicate_files_in_session.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#' @eval options::as_params()
#' @name options_params
#'
NULL

#' Check Whether Filenames Already Exist in a Session
#'
#' @description Ask the server which of the supplied filenames already
#' exist as files in the given session. Useful before bulk uploads to detect
#' name collisions in advance.
#'
#' @param vol_id Target volume number. Must be a positive integer.
#' @param session_id Numeric session identifier. Must be a positive integer.
#' @param filenames Character vector of filenames to check. Length must be
#' at least 1; each element must be a non-empty string.
#' @param rq An \code{httr2} request object. Defaults to \code{NULL}.
#'
#' @return A \code{tibble} with columns \code{filename} (character) and
#' \code{exists} (logical), one row per input filename and in the same
#' order. Returns \code{NULL} if the request fails.
#'
#' @inheritParams options_params
#'
#' @examples
#' \donttest{
#' \dontrun{
#' check_duplicate_files_in_session(
#' vol_id = 1,
#' session_id = 42,
#' filenames = c("clip_001.mp4", "clip_002.mp4")
#' )
#' }
#' }
#' @export
check_duplicate_files_in_session <- function( # nolint: object_length_linter.
vol_id = 1,
session_id,
filenames,
vb = options::opt("vb"),
rq = NULL
) {
assert_positive_integer(vol_id, "vol_id")
assert_positive_integer(session_id, "session_id")

assertthat::assert_that(
is.character(filenames),
length(filenames) >= 1,
msg = "filenames must be a non-empty character vector"
)
assertthat::assert_that(
!any(is.na(filenames)),
all(nzchar(trimws(filenames))),
msg = "filenames must not contain NA or empty strings"
)

assertthat::assert_that(is.logical(vb), length(vb) == 1)
assertthat::assert_that(is.null(rq) || inherits(rq, "httr2_request"))

# `as.list()` on a length-1 character would still serialize to a JSON array
# via httr2, but be explicit so the contract matches the server's expected
# `[...]` shape regardless of length.
body <- list(filenames = as.list(filenames))

result <- perform_api_post(
path = sprintf(API_SESSION_CHECK_DUPLICATE_FILES, vol_id, session_id),
body = body,
rq = rq,
vb = vb
)

if (is.null(result) || isTRUE(result)) {
if (vb) {
message(
"Failed to check duplicate filenames in session ",
session_id, " of volume ", vol_id
)
}
return(NULL)
}

tibble::tibble(
filename = vapply(result, function(r) as.character(r$filename), character(1)),
exists = vapply(result, function(r) isTRUE(r$exists), logical(1))
)
}
Loading
Loading