From b8d4a43b3ef3e1e61192ff0bfb8a102c8298aef2 Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Wed, 27 Nov 2024 16:23:39 +0100 Subject: [PATCH 1/6] Allow connecting to private LaminDB instances --- CHANGELOG.md | 4 ++++ R/InstanceAPI.R | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47c0d61..fdfd511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # laminr v0.2.1 +## BUG FIXES + +* Allow connecting to private LaminDB instances (PR #xxx). + ## DOCUMENTATION * Update the laminr Getting Started vignette with feedback from demo (PR #113). diff --git a/R/InstanceAPI.R b/R/InstanceAPI.R index 1038b53..35381af 100644 --- a/R/InstanceAPI.R +++ b/R/InstanceAPI.R @@ -31,7 +31,19 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter "/schema" ) - response <- httr::GET(url) + headers <- httr::add_headers( + accept = "application/json", + `Content-Type` = "application/json" + ) + user_settings <- .get_user_settings() + if (!is.null(user_settings$access_token)) { + headers$Authorization <- paste("Bearer", user_settings$access_token) + } + + response <- httr::GET( + url, + headers + ) private$process_response(response, "get schema") }, @@ -92,6 +104,15 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) + headers <- httr::add_headers( + accept = "application/json", + `Content-Type` = "application/json" + ) + user_settings <- .get_user_settings() + if (!is.null(user_settings$access_token)) { + headers$Authorization <- paste("Bearer", user_settings$access_token) + } + if (verbose) { cli_inform("URL: {url}") cli_inform("Body: {jsonlite::minify(body)}") @@ -99,10 +120,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - httr::add_headers( - accept = "application/json", - `Content-Type` = "application/json" - ), + headers, body = body ) @@ -180,6 +198,15 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) + headers <- httr::add_headers( + accept = "application/json", + `Content-Type` = "application/json" + ) + user_settings <- .get_user_settings() + if (!is.null(user_settings$access_token)) { + headers$Authorization <- paste("Bearer", user_settings$access_token) + } + if (verbose) { cli_inform("URL: {url}") cli_inform("Body: {jsonlite::minify(body)}") @@ -187,10 +214,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - httr::add_headers( - accept = "application/json", - `Content-Type` = "application/json" - ), + headers, body = body ) From 0e052a190ecd2c7431b7a8072c304dcb0f847fcc Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Wed, 27 Nov 2024 16:24:01 +0100 Subject: [PATCH 2/6] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdfd511..f046e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## BUG FIXES -* Allow connecting to private LaminDB instances (PR #xxx). +* Allow connecting to private LaminDB instances (PR #118). ## DOCUMENTATION From 749fae4714db6d3b00128e0fb607bc25190c4c16 Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Wed, 27 Nov 2024 16:42:30 +0100 Subject: [PATCH 3/6] fix headers --- R/InstanceAPI.R | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/R/InstanceAPI.R b/R/InstanceAPI.R index 35381af..c699c92 100644 --- a/R/InstanceAPI.R +++ b/R/InstanceAPI.R @@ -31,18 +31,18 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter "/schema" ) - headers <- httr::add_headers( + headers <- c( accept = "application/json", `Content-Type` = "application/json" ) user_settings <- .get_user_settings() if (!is.null(user_settings$access_token)) { - headers$Authorization <- paste("Bearer", user_settings$access_token) + headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) } response <- httr::GET( url, - headers + httr::add_headers(.headers = headers) ) private$process_response(response, "get schema") @@ -104,13 +104,13 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) - headers <- httr::add_headers( + headers <- c( accept = "application/json", `Content-Type` = "application/json" ) user_settings <- .get_user_settings() if (!is.null(user_settings$access_token)) { - headers$Authorization <- paste("Bearer", user_settings$access_token) + headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) } if (verbose) { @@ -120,7 +120,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - headers, + httr::add_headers(.headers = headers), body = body ) @@ -198,13 +198,13 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) - headers <- httr::add_headers( + headers <- c( accept = "application/json", `Content-Type` = "application/json" ) user_settings <- .get_user_settings() if (!is.null(user_settings$access_token)) { - headers$Authorization <- paste("Bearer", user_settings$access_token) + headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) } if (verbose) { @@ -214,7 +214,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - headers, + httr::add_headers(.headers = headers), body = body ) From 06d243ff91d4b32a8cf2ba8f20c9e878827fb0bf Mon Sep 17 00:00:00 2001 From: Robrecht Cannoodt Date: Wed, 27 Nov 2024 17:10:06 +0100 Subject: [PATCH 4/6] parse 'null' as NULL --- R/settings_store.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/settings_store.R b/R/settings_store.R index 928ce40..5289427 100644 --- a/R/settings_store.R +++ b/R/settings_store.R @@ -90,11 +90,10 @@ } raw_type <- field_types[[name]] - optional <- grepl("Optional\\[.*\\]", raw_type) type <- gsub("Optional\\[(.*)\\]", "\\1", raw_type) value <- - if (optional && raw_value == "null") { + if (raw_value == "null") { NULL } else if (type == "str") { raw_value From f6c6ca9b578c3c7019e382c51f18cc32634305d3 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 28 Nov 2024 10:18:53 +0100 Subject: [PATCH 5/6] Add test connecting to private instance --- .../{test-connect_lamindata.R => test-connect.R} | 9 +++++++++ 1 file changed, 9 insertions(+) rename tests/testthat/{test-connect_lamindata.R => test-connect.R} (77%) diff --git a/tests/testthat/test-connect_lamindata.R b/tests/testthat/test-connect.R similarity index 77% rename from tests/testthat/test-connect_lamindata.R rename to tests/testthat/test-connect.R index fdc1fb9..e189041 100644 --- a/tests/testthat/test-connect_lamindata.R +++ b/tests/testthat/test-connect.R @@ -24,3 +24,12 @@ test_that("Connecting to lamindata works", { expect_s3_class(artifact$wells, "RelatedRecords") # one-to-many }) + +test_that("Connecting to a private instance works", { + skip_if_not_logged_in() + + db <- connect("laminlabs/lamin-dev") + + instance_settings <- db$get_settings() + expect_equal(instance_settings$name, "lamin-dev") +}) From 769e3a208693abbb434810ff2c092c25e88f82b1 Mon Sep 17 00:00:00 2001 From: Luke Zappia Date: Thu, 28 Nov 2024 10:36:37 +0100 Subject: [PATCH 6/6] Add private InstanceAPI method to get headers --- R/InstanceAPI.R | 62 ++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/R/InstanceAPI.R b/R/InstanceAPI.R index c699c92..6c62143 100644 --- a/R/InstanceAPI.R +++ b/R/InstanceAPI.R @@ -31,18 +31,9 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter "/schema" ) - headers <- c( - accept = "application/json", - `Content-Type` = "application/json" - ) - user_settings <- .get_user_settings() - if (!is.null(user_settings$access_token)) { - headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) - } - response <- httr::GET( url, - httr::add_headers(.headers = headers) + httr::add_headers(.headers = private$get_headers()) ) private$process_response(response, "get schema") @@ -104,15 +95,6 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) - headers <- c( - accept = "application/json", - `Content-Type` = "application/json" - ) - user_settings <- .get_user_settings() - if (!is.null(user_settings$access_token)) { - headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) - } - if (verbose) { cli_inform("URL: {url}") cli_inform("Body: {jsonlite::minify(body)}") @@ -120,7 +102,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - httr::add_headers(.headers = headers), + httr::add_headers(.headers = private$get_headers()), body = body ) @@ -198,15 +180,6 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter tolower(include_foreign_keys) ) - headers <- c( - accept = "application/json", - `Content-Type` = "application/json" - ) - user_settings <- .get_user_settings() - if (!is.null(user_settings$access_token)) { - headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) - } - if (verbose) { cli_inform("URL: {url}") cli_inform("Body: {jsonlite::minify(body)}") @@ -214,7 +187,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::POST( url, - httr::add_headers(.headers = headers), + httr::add_headers(.headers = private$get_headers()), body = body ) @@ -226,13 +199,6 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter registry_name, id_or_uid, verbose = FALSE) { - user_settings <- .get_user_settings() - if (is.null(user_settings$access_token)) { - cli::cli_abort(c( - "There is no access token for the current user", - "i" = "Run {.code lamin login} and reconnect to the database in a new R session" - )) - } url <- paste0( private$.instance_settings$api_url, @@ -255,9 +221,7 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter response <- httr::DELETE( url, httr::add_headers( - accept = "application/json", - `Content-Type` = "application/json", - Authorization = paste("Bearer", user_settings$access_token) + .headers = private$get_headers(authorization_required = TRUE) ) ) @@ -286,6 +250,24 @@ InstanceAPI <- R6::R6Class( # nolint object_name_linter ), private = list( .instance_settings = NULL, + get_headers = function(authorization_required = FALSE) { + headers <- c( + accept = "application/json", + `Content-Type` = "application/json" + ) + user_settings <- .get_user_settings() + + if (!is.null(user_settings$access_token)) { + headers[["Authorization"]] <- paste("Bearer", user_settings$access_token) + } else if (authorization_required) { + cli::cli_abort(c( + "There is no access token for the current user", + "i" = "Run {.code lamin login} and reconnect to the database in a new R session" + )) + } + + return(headers) + }, process_response = function(response, request_type) { content <- httr::content(response) if (httr::http_error(response)) {