2

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)
troh
  • 1,354
  • 10
  • 19
  • Sorry, no answer yet, but here is an answer [how to generate a download link to an existing file](https://stackoverflow.com/a/33417165/12647315). Maybe this is a starting point for you – starja Sep 18 '20 at 22:00
  • I did see that but with ```downloadHandler``` what's the best way to do that with table links? That works well for when you're using a ```downloadButton``` but how do you scale beyond a single file dl? – troh Sep 18 '20 at 22:07
  • You could try : https://stackoverflow.com/a/57978298/13513328 – Waldi Sep 21 '20 at 19:08
  • Can you please elaborate regarding the multi user scenario you mentioned below? What is the expected behaviour? – ismirsehregal Sep 23 '20 at 10:00

2 Answers2

0

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)
  })
  
}
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • I have a current implementation that wipes the entire tmp folder, but it will do that for any session that ends leaving current users without the pdf to download. How would this work for multi-users? Reactive values don't work in `session$onSessionEnded`. – troh Sep 22 '20 at 17:30
  • Also, the current download doesn't work because it doesn't point to the filesystem temp folder. It points to http:////tmp/RXXXXX. I need it to point to /tmp/RXXXX. – troh Sep 22 '20 at 17:33
  • @troh Sorry I don't understand. You want to delete the temporary files? Why? Otherwise, you could convert the PDF to base64 encoding. – Stéphane Laurent Sep 24 '20 at 08:32
0

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)
Michael Dewar
  • 2,553
  • 1
  • 6
  • 22