Search code examples
rofficer

How to write multiple docx files in purrr::map() style with officer from within downloadHandler() in Shiny to temp directory?


I am trying to write multiple docx files from within downloadHandler(). When purrr::map() arrives at the part of the mapped function where the resume is written with a unique name to the specified temp directory, that is then zipped and returned to the file argument of downloadHandler(). There is an error stating that the specified directory does not exist. An example directory for a single resume is /var/folders/vv/57k257g531b889lqwcgj2z3m0000gp/T//RtmpqhDbg1/resumes/someones_name_resume.docx

I have tried many ways of writing the files to different locations or altering the end directory. I am working from within an R project. I keep getting the error: "Warning: Error in : directory of /var/folders/vv/57k257g531b889lqwcgj2z3m0000gp/T//RtmpqhDbg1/resumes/someones_name_resume.docx does not exist."

resume_temp <- file.path(tempdir(), "resumes")
make_my_resume <- function(my_id) {


  # the empty Word doc that has an applied resume style
  template <- read_docx(here::here("r_scripts", "modern_basic_resume_empty.docx"))


  name_for_file <- str_to_lower(paste(my$first_name, my$last_name, sep = "_"))


  #-----------------------build resume in Word------------------------------------

  word_resume <- template %>%
    cursor_begin() %>% 
    body_remove() %>%
    body_add_par(paste(my$first_name, my$last_name), style = "Title") %>%

    body_end_section_continuous() %>%
    body_add_par(my$address, style = "Contact Info") %>%
    body_add_par(my$phone, style = "Contact Info") %>%
    body_add_par(my$email, style = "Contact Info") %>%

    body_end_section_continuous() %>%
    body_add_par(" ", style = "Title") %>%
    body_add_par(" ", style = "Normal") %>%

    body_end_section_continuous() %>%
    body_add_par("Experience", style = "heading 1") %>%
    body_add_table(my_experience, style = "Plain Table 5") %>%

    body_end_section_continuous() %>%
    body_add_par("Deployments", style = "heading 1") %>%
    body_add_table(my_deployments, style = "Plain Table 5") %>%

    body_end_section_continuous() %>%
    body_add_par("Education", style = "heading 1") %>%
    body_add_table(my_education, style = "Plain Table 5") %>%

    body_end_section_continuous() %>%
    body_add_par("Certifications", style = "heading 1") %>%
    body_end_section_continuous()

  # iterate over each certification
  for (cert in my_certificates$certs) {
    eval(parse(text = (paste0("word_resume <- body_add_par(word_resume, ",
                              "'", cert, "'",
                              ", ",
                              "style = 'List Bullet')",
                              collapse = ""))))
  }

  word_resume <- word_resume %>%  
    body_end_section_columns() %>%
    body_add_par("SKILLS", style = "heading 1") %>%
    body_end_section_continuous()

  # iterate over each skill
  for (skill in my_skills$skills) {
    eval(parse(text = (paste0("word_resume <- body_add_par(word_resume, ",
                              "'", skill, "'",
                              ", ",
                              "style = 'List Bullet')",
                              collapse = ""))))
  }

  message("------starting to write resumes to file------")
  # finish and write to disk

  # browser()

  # resume_empty_dir <- paste0(resume_temp, "/", name_for_file, "_resume.docx")
  # 
  # write_file()

  word_resume <- word_resume %>%  
    body_end_section_columns() %>% 
    print(target = file.path(resume_temp, paste0(name_for_file, "_resume.docx")))


}
output$resume <- downloadHandler(

    filename = "resumes.zip",
    content = function(file, resume_temp) {

      # resume_temp <- here::here(tempdir(), "resumes")

      # file <- NULL

      message("----starting map2()----")

      # browser()

      require(purrr)
      purrr::map(
        .x = selectedId(),  # reactive list for my_id argument in         # make_my_resume
        .f = make_my_resume
      )

      message("----map2() finished----")

      zip::zipr(zipfile = file, files = resume_temp)
      message("----files zipped----")

    },
    contentType = "application/zip"
  )

I want to have the resumes written to a temp directory that is zipped and returned to the file argument of downloadHandler(). Thank you so much!


Solution

  • I found the solution. Instead of creating my tempdir (outside of the app) to write to as

    temp_path <- file.path(tempdir(), "sub_directory")
    

    I created it as just

    temp_path <- file.path(tempdir())
    

    Once the docx files were written to temp_path, I used a combination of list.files() and regex to zip up and return only the files I wanted, as there are some other unwanted directories created along with the docx files. I used the following inside the downloadHandler() content function after purr:map() wrote the docx files to my temp directory:

    to_keep <- list.files(temp_path, pattern = ".docx$", full.names = TRUE)
    
    all_temp_files <- list.files(temp_path, full.names = TRUE)
    
    to_remove <- setdiff(all_temp_files, to_keep)
    
    unlink(to_remove, recursive = TRUE, force = TRUE)
    
    zip::zipr(zipfile = file, files = temp_path)
    

    I am still not sure why

    temp_path <- file.path(tempdir(), "sub_directory")
    

    does not work though.