Download uploaded PDFs from Shiny App and delete files on close

Viewed 335

I have a shiny app that uploads pdfs to do some checks on them and write a report to a table for the user to see. One of the requirements is to create a link to the document that downloads the initial uploaded pdf. Is there a way to access the temp directory files for download and put that download link in a DT datatable? I've tried coping files to www and they can be accessed that way but when the session ends the files are not deleted.

library(shiny)
library(DT)
ui <- fluidPage(
    fileInput('pdfFile',
              'Upload PDF',
              multiple = TRUE,
              accept = c('.pdf')),
    DTOutput('Table')
)

server <- function(input, output) {

    output$Table <- renderDT({
        pdfTable <- cbind(input$pdfFile,
              pdflink = sprintf('<a href="%s" download="%s">%s</a>',
                           input$pdfFile$datapath,
                           input$pdfFile$name,
                           input$pdfFile$name),
              stringsAsFactors = FALSE)
        datatable(pdfTable,escape = FALSE)
    })
}

shinyApp(ui = ui, server = server)
2 Answers

You can use session$onSessionEnded to execute some code after the client has disconnected (I confess I never tried):

server <- function(input, output, session) {
  
  session$onSessionEnded(function(){
    file.remove(......)
  })
  
  output$Table <- renderDT({
    pdfTable <- cbind(input$pdfFile,
                      pdflink = sprintf('<a href="%s" download="%s">%s</a>',
                                        input$pdfFile$datapath,
                                        input$pdfFile$name,
                                        input$pdfFile$name),
                      stringsAsFactors = FALSE)
    datatable(pdfTable, escape = FALSE)
  })
  
}

I wasn't able to get the downloadButton to appear in the table, but the otherwise I believe the following meets your requirements. The basic idea is to copy the uploaded file to a new tempfile whose location gets saved in a reactiveVal until needed.

library(shiny)
library(tidyverse)
library(DT)

ui <- fluidPage(
  fileInput('pdfFile',
            'Upload PDF',
            multiple = TRUE,
            accept = c('.pdf')),
  downloadButton("download_button", "Download Selected File"),
  DTOutput('Table')
)

server <- function(input, output) {
  
  output$Table <- renderDT({
    uploaded_df() %>% 
      select(-temp) %>% 
      datatable(selection = "single")
  })
  
  uploaded_df <- reactiveVal(tibble(name = character(), temp = character()))
  
  observeEvent(input$pdfFile,{

    temp_file_location <- tempfile(fileext = ".pdf")
    file.copy(input$pdfFile$datapath, temp_file_location)
    
    tibble(name = input$pdfFile$name,
           temp = temp_file_location) %>% 
      bind_rows(uploaded_df(), .) %>% 
      uploaded_df()
    
  })
  
  output$download_button <- downloadHandler(
    filename <- function() {
      req(input$Table_rows_selected)
      uploaded_df()$name[[input$Table_rows_selected]]
    },
    
    content <- function(file) {
      file.copy(uploaded_df()$temp[[input$Table_rows_selected]], file)
    }
  )
}

shinyApp(ui = ui, server = server)
Related