R/exportFiles.R

Defines functions exportFiles exportFiles.redcapDbConnection exportFiles.redcapApiConnection

Documented in exportFiles exportFiles.redcapApiConnection exportFiles.redcapDbConnection

#' @name exportFiles
#' 
#' @title Exports a File attached to a Record
#' @description A single file from a single record is retrieved.  The behavior 
#' of this function is consistent with the behavior of the API, which only 
#' allows one file to be downloaded at a time
#' 
#' @param rcon A REDCap connection object as generated by \code{redcapConnection}
#' @param record The record ID in which the desired file is stored. Must be length 1.
#' @param field The field name in which the file is stored. Must be length 1. 
#' @param event The event name for the file.  Must be length 1.  
#'   This applies only to longitudinal projects.  If the event is not
#'   supplied for a longitudinal project, the API will return an error message
#' @param dir A directory/folder to which the file will be saved. 
#'   By default, the working directory is used
#' @param filePrefix Logical.  Determines if a prefix is appended to the file 
#'   name.  The prefix takes the form [record_id]-[event_name]-[file_name].  
#'   The file name is always the same name of the file as it exists in REDCap
#' @param ... Arguments to be passed to other methods
#' @param bundle A \code{redcapBundle} object as created by \code{exportBundle}.
#' @param error_handling An option for how to handle errors returned by the API.
#'   see \code{\link{redcap_error}}
#' 
#' @details The function may only export a single file.  
#' See the examples for suggestions on exporting multiple files.
#' 
#' Note that the name of the file can not be changed.  Whatever name exists in 
#' REDCap is the name that will be used, although the record ID and event name 
#' may be appended as a prefix
#' 
#' @section REDCap API Documentation (6.5.0):
#' This method allows you to download a document that has been attached to an 
#' individual record for a File Upload field. Please note that this method may also 
#' be used for Signature fields (i.e. File Upload fields with "signature" validation type).
#' 
#' Note about export rights: Please be aware that Data Export user rights will be 
#' applied to this API request. For example, if you have "No Access" data export rights 
#' in the project, then the API file export will fail and return an error. And if you 
#' have "De-Identified" or "Remove all tagged Identifier fields" data export rights, 
#' then the API file export will fail and return an error *only if* the File Upload 
#' field has been tagged as an Identifier field. To make sure that your API request 
#' does not return an error, you should have "Full Data Set" export rights in the project.
#' 
#' @section REDCap Version:
#' 5.8.2+ 
#' 
#' @section Known REDCap Limitations:
#' None
#' 
#' @author Benjamin Nutter
#' 
#' @references
#' Please refer to your institution's API documentation.
#' 
#' Additional details on API parameters are found on the package wiki at
#' \url{https://github.com/nutterb/redcapAPI/wiki/REDCap-API-Parameters}
#' 
#' @export

exportFiles <- function(rcon, record, field, event, dir, filePrefix=TRUE, ...,
                        bundle = getOption("redcap_bundle"))
  UseMethod("exportFiles")

#' @rdname exportFiles
#' @export

exportFiles.redcapDbConnection <- function(rcon, record, field, event, dir, filePrefix=TRUE, ..., 
                                           bundle = getOption("redcap_bundle")){
  message("Please accept my apologies.  The exportFiles method for redcapDbConnection objects\n",
          "has not yet been written.  Please consider using the API.")
}

#' @rdname exportFiles
#' @export

exportFiles.redcapApiConnection <- function(rcon, record, field, event = NULL, 
                                            dir, 
                                            filePrefix=TRUE, ...,
                                            bundle = getOption("redcap_bundle"),
                                            error_handling = getOption("redcap_error_handling")){
  
  if (!is.na(match("proj", names(list(...)))))
  {
    message("The 'proj' argument is deprecated.  Please use 'bundle' instead")
    bundle <- list(...)[["proj"]]
  }

  if (is.numeric(record)) record <- as.character(record)
  
  #* Error Collection Object
  coll <- checkmate::makeAssertCollection()
  
  massert(~ rcon + bundle,
          fun = checkmate::assert_class,
          classes = list(rcon = "redcapApiConnection",
                         bundle = "redcapBundle"),
          null.ok = list(rcon = FALSE,
                         bundle = TRUE),
          fixed = list(add = coll))
  
  massert(~ record + field + event,
          fun = checkmate::assert_character,
          null.ok = list(record = FALSE,
                         field = FALSE,
                         event = TRUE),
          fixed = list(len = 1,
                       add = coll))
  
  if (missing(dir)){
    coll$push("'dir' must have a character(1) value")
  }
  else{
    checkmate::assert_character(x = dir,
                                len = 1, 
                                add = coll)
    
    if (is.character(dir)){
      if (!dir.exists(dir)){
        coll$push("'dir' is not an existing directory")
      }
    }
  }
  
  checkmate::assert_logical(x = filePrefix,
                            len = 1,
                            add = coll)
  
  checkmate::reportAssertions(coll)
  
  #* Secure the meta_data
  meta_data <- 
    if (is.null(bundle$meta_data)) 
      exportMetaData(rcon)
    else 
      bundle$meta_data
  
  #* make sure 'field' exist in the project and are 'file' fields
  if (!field %in% meta_data$field_name) 
  {
    coll$push(paste("'", field, "' does not exist in the project.", sep=""))
  }
  else if (meta_data$field_type[meta_data$field_name == field] != "file")
  {
    coll$push(paste0("'", field, "' is not of field type 'file'"))
  }
  
  #* Secure the events list
  events_list <- 
    if (is.null(bundle$events))
      exportEvents(rcon)
    else
      bundle$events
      
  #* make sure 'event' exists in the project
  if (inherits(events_list, "data.frame"))
  {
    if (!event %in% events_list$unique_event_name) 
      coll$push(paste0("'", event, "' is not a valid event name in this project."))
  }
  
  checkmate::reportAssertions(coll)
  
  body <- list(token = rcon$token, 
               content = 'file',
               action = 'export', 
               returnFormat = 'csv',
               record = record,
               field = field)
  
  if (!is.null(event)) body[['event']] <- event
  
  #* Export the file
  x <- httr::POST(url = rcon$url, 
                  body = body, 
                  config = rcon$config)

  if (x$status_code != 200) redcap_error(x, error_handling)
  
  #* strip the returned character string to just the file name.
  filename <- sub(pattern = "[[:print:]]+; name=", 
                 replacement = "", 
                 x = x$headers$'content-type')
  filename <- gsub(pattern = "\"", 
                   replacement = "", 
                   filename)
  filename <- sub(pattern = ";charset[[:print:]]+", 
                  replacement = "", 
                  x = filename)
    
  #* Add the prefix
  if (filePrefix) filename <- paste(record, "-", event, "-", filename, sep="")
    
  #* Write to a file
  writeBin(object = as.vector(x$content), 
           con = file.path(dir, filename), 
           useBytes=TRUE)
  
  message("The file was saved to '", filename, "'")

}

Try the redcapAPI package in your browser

Any scripts or data that you put into this service are public.

redcapAPI documentation built on Feb. 18, 2020, 1:09 a.m.