diff --git a/DESCRIPTION b/DESCRIPTION index 4feb2f7..7a17f75 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: redcapcustodian Type: Package Title: Data automation for R-centric workflows with a nod towards REDCap -Version: 1.21.0 +Version: 1.22.0 Authors@R: c( person("Philip", "Chase", email = "pbc@ufl.edu", @@ -70,6 +70,6 @@ Suggests: tidyverse VignetteBuilder: knitr Config/testthat/edition: 3 -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Depends: R (>= 3.5.0) diff --git a/Dockerfile b/Dockerfile index 0860e29..5b0b123 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,13 @@ -FROM --platform=linux/amd64 rocker/verse:4.3.2 +FROM --platform=linux/amd64 rocker/verse:4.3.3 WORKDIR /home/rocker RUN apt update -y && apt install -y libmariadb-dev libmariadb-dev-compat RUN apt install -y --no-install-recommends libxt6 +# returns an error but tlmgr is updated to 2024 regardless +RUN wget ${CTAN_REPO}/update-tlmgr-latest.sh && bash update-tlmgr-latest.sh; exit 0 + # install necessary libraries RUN R -e "install.packages(c( \ 'DBI', \ diff --git a/NEWS.md b/NEWS.md index 9aedd34..37576b2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# redcapcustodian 1.22.0 (released 2024-03-26) +- Implement hacky fix for tlmgr 2023 being unable to install packages (@ChemiKyle, #156) +- Fix bug that prevented email_body from being included in email (@ljwoodley, @ChemiKyle, #155) +- Add 'Scraping one user's API tokens' section to vignettes/credential-scraping.Rmd (@pbchase, @ChemiKyle, #154) +- Update scrape_user_api_tokens() to tidyselect 1.2 standards (@pbchase, #154) + # redcapcustodian 1.21.0 (released 2024-03-15) - Add attachment management to send_email() allowing lists of files or dataframes to be attached to an email (@ljwoodley, #152, #153) diff --git a/R/credential_management.R b/R/credential_management.R index cae2684..396203b 100644 --- a/R/credential_management.R +++ b/R/credential_management.R @@ -22,7 +22,7 @@ scrape_user_api_tokens <- function(conn, username_to_scrape = Sys.info()[["user" # collect super API token if one exists super_credentials <- dplyr::tbl(conn, "redcap_user_information") %>% dplyr::filter(.data$username == username_to_scrape) %>% - dplyr::select(.data$username, .data$api_token) %>% + dplyr::select("username", "api_token") %>% dplyr::collect() %>% dplyr::mutate(project_id = 0) %>% dplyr::filter(!is.na(.data$api_token)) %>% @@ -32,16 +32,16 @@ scrape_user_api_tokens <- function(conn, username_to_scrape = Sys.info()[["user" dplyr::filter(.data$username == username_to_scrape) %>% dplyr::filter(!is.na(.data$api_token)) %>% dplyr::select( - .data$project_id, - .data$username, - .data$api_token + "project_id", + "username", + "api_token" ) %>% # add project information dplyr::left_join( dplyr::tbl(conn, "redcap_projects") %>% dplyr::select( - .data$project_id, - .data$app_title + "project_id", + "app_title" ), by = "project_id" ) %>% @@ -49,8 +49,8 @@ scrape_user_api_tokens <- function(conn, username_to_scrape = Sys.info()[["user" # bind_rows used over rbind to avoid need to align column order dplyr::bind_rows(super_credentials) %>% dplyr::rename( - project_display_name = .data$app_title, - token = .data$api_token # rename for compatibility with REDCapR credential objects + project_display_name = "app_title", + token = "api_token" # rename for compatibility with REDCapR credential objects ) return(credentials) diff --git a/R/logging.R b/R/logging.R index 19135fe..36679dd 100644 --- a/R/logging.R +++ b/R/logging.R @@ -689,9 +689,10 @@ send_email <- email_to <- unlist(strsplit(email_to, " ")) } + email_content <- email_body + if (!is.null(file_name)) { output_dir <- tempdir() - email_content <- list() if (!is.null(df_to_email) && is.data.frame(df_to_email)) { df_to_email <- list(df_to_email) diff --git a/VERSION b/VERSION index 3500250..57807d6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.21.0 +1.22.0 diff --git a/vignettes/credential-scraping.Rmd b/vignettes/credential-scraping.Rmd index a875daf..b8aa6fa 100644 --- a/vignettes/credential-scraping.Rmd +++ b/vignettes/credential-scraping.Rmd @@ -115,6 +115,79 @@ dbDisconnect(file_conn) dbDisconnect(source_conn) ``` +### Scraping one user's API tokens + +Scraping one user's API tokens and putting them in a new, local sqlite DB for use. + +You must provide the username in the API_USER environment variable or on the command line. To specify it on the command line via `Rscript` and specify a REDCap username. e.g. + +```sh +Rscript scrape_one_user.R jane_doe +``` + +```{r, eval = FALSE} +library(redcapcustodian) +library(DBI) +library(tidyverse) +library(dotenv) + +# Get the username provided on the command line if one is provided. +# Otherwise, get the username form the environment. +# Otherwise, exit. +args <- commandArgs(trailingOnly = TRUE) +if (length(args) > 0) { + # Use the command line argument + username <- args +} else if (Sys.getenv("API_USER") != "") { + # Use the environment variable + username <- Sys.getenv("API_USER") +} else { + # Exit + warning("Please provide a username that whose API tokens you want to read either on the command line or via the API_USER environment variable. No action taken.") + quit() +} + +# Creates the credentials file if one does not exists. +# Otherwise it deletes the credentials file +credentials_db_path <- here::here(paste0("credentials-", username, ".db")) +if (fs::file_exists(credentials_db_path)) fs::file_delete(credentials_db_path) +file_conn <- DBI::dbConnect(RSQLite::SQLite(), credentials_db_path) + +# SQLite friendly schema +credentials_sql <- "CREATE TABLE IF NOT EXISTS `credentials` ( + `redcap_uri` TEXT NOT NULL, + `server_short_name` varchar(128) NOT NULL, + `username` varchar(191) NOT NULL, + `project_id` int(10) NOT NULL, + `project_display_name` TEXT NOT NULL, + `project_short_name` varchar(128) DEFAULT NULL, + `token` varchar(64) NOT NULL, + `comment` varchar(256) DEFAULT NULL +); +" + +dbExecute(file_conn, credentials_sql) + +# Connect to the REDCap database specified in the environment +# loaded by the dotenv library +source_conn <- connect_to_redcap_db() +source_credentials <- scrape_user_api_tokens( + conn = source_conn, + username_to_scrape = username +) + +# alter credentials to match local schema +source_credentials_upload <- source_credentials %>% + mutate( + redcap_uri = Sys.getenv("URI"), + server_short_name = tolower(Sys.getenv("INSTANCE")) + ) + +dbAppendTable(file_conn, "credentials", source_credentials_upload) + +dbDisconnect(file_conn) +dbDisconnect(source_conn) +``` ### Creating API tokens for all local projects ```{r, eval = FALSE}