R/compile_teach_it.R

Defines functions compile_teach_it

Documented in compile_teach_it

#' compile_teach_it
#'
#' Compile Teaching Materials from a project's 'teach-it.gsheet'. Also renames folders based on info in the Titles tab and invokes [sweep_teaching_materials()] to relocate scrap working files.
#'
#' @param WD is working directory of the project; easiest way to supply a different lesson is with "?", which will invoke [parse_wd()]; default is WD=getwd()
#' @param teach_it_drib if you already have the teach-it.gsheet dribble looked up from [drive_find_path()], passing this object can can save some time; default = NULL
#' @param rename_lessons logical; do you want to rename lesson folders based on Titles tab? default= T takes about 2sec to check if nothing needs changing; uses helper function [zrename_lessons()]
#' @param prompt_rename logical, do you want to prompt user about whether to rename lessons? default=FALSE
#' @return tibble of the compiled standards data; a JSON is saved to meta/JSON/teaching-materials.json
#' @importFrom rlang .data
#' @export

compile_teach_it <- function(WD = "?",
                             teach_it_drib = NULL,
                             rename_lessons = TRUE,
                             prompt_rename = FALSE) {
  WD <- parse_wd(WD)
  WD_git <- get_wd_git(WD = WD)
  . = NULL #to avoid errors with dplyr syntax
  #Keep teaching-materials/ folder tidy
  sweep_teaching_materials(WD = WD)
  message("running compile_teach_it()...")
  #Get front matter from the project working directory
  fm <- get_fm(WD_git = WD_git)

  status <- fm$PublicationStatus
  gdrivehome <- fm$GdriveHome
  checkmate::assert_choice(status,
                           c("Proto", "Hidden", "Beta", "Coming Soon", "Live", "Draft", "Upcoming"))#draft deprecated; Upcoming/Coming Soon confusion needs to be sorted out
  checkmate::assert_choice(gdrivehome, c("GP-Studio", "GP-LIVE"))
  if (gdrivehome == "GP-Studio") {
    tmID <- fm$GdriveTeachMatID
  } else{
    tmID <- fm$GdrivePublicID
  }
  checkmate::assert_character(tmID, min.chars = 6)

  if (is.null(teach_it_drib)) {
    teachitID <- fm$GdriveTeachItID
    checkmate::assert_character(teachitID, all.missing = FALSE)
    teach_it_drib <- drive_find_path(teachitID)
  }
  #check that teach_it_drib has 1 row and is a data frame
  checkmate::assert_data_frame(teach_it_drib, nrows = 1)


  tlinks0 <-
    googlesheets4::read_sheet(
      teach_it_drib,
      sheet = "TeachMatLinks",
      skip = 1,
      col_types = "c",

    )

  #****
  #It's annoying, but I want to keep the _lsn on the links page
  #because it distinguishes where the user of the teach-it.gsheet
  #should type in the lsn number (lsn) and when they should not, b/c it's auto (_lsn)


  # Handle materials for multiple lessons (e.g. P1&2) -------------------------
  # Want to break up L1&2 entries and repeat data for 1 and 2, so lessons
  # get the shared info
  multipart_material <-
    grepl("&", tlinks0$`_lsn`) %>% which()

  if (length(multipart_material) > 0) {
    multi_df <- tlinks0[multipart_material,]
    nonmulti_df <- tlinks0[-multipart_material,]
    lessons <- stringr::str_split(multi_df$`_lsn`, "&")
    expanded_multi <- lapply(1:length(lessons), \(i) {
      lsn_i <- lessons[[i]]
      multi_df_i <- multi_df[rep(i, length(lsn_i)),] %>%
        dplyr::mutate(`_lsn` = lsn_i)
    }) %>% dplyr::bind_rows()
    #combine expanded (repeated) data with previous data
    tlinks0 <-
      dplyr::bind_rows(nonmulti_df, expanded_multi) %>%
      #rearrange to preserve order of output
      dplyr::arrange(
        !.data$`_itemType` == "teachMatDir",
        .data$`_envir`,
        .data$`_grades`,
        .data$`_itemType` != "variantDir",
        #put variantDir link above all the lessons
        .data$`_lsn`,
        .data$`_fileType`
      )
  }

  #rename `_code` to code for ease
  #and b/c we're not rewriting data to spreadsheet
  mlinks <-
    googlesheets4::read_sheet(
      teach_it_drib,
      sheet = "Multimedia",
      skip = 1,
      col_types = "c",

    ) %>%
    dplyr::rename(code = .data$`_code`) %>%
    dplyr::filter(!is.na(.data$code)) %>%
    dplyr::arrange(.data$order) %>%
    dplyr::select(1:dplyr::starts_with("otherLink"))

  #unit info
  uinfo <-
    googlesheets4::read_sheet(
      teach_it_drib,
      sheet = "Titles",
      skip = 1,
      col_types = "c"
    )

  lext <-
    googlesheets4::read_sheet(
      teach_it_drib,
      sheet = "LsnExt",
      skip = 1,
      col_types = "c"
    ) %>% dplyr::filter(.data$link != "URL" &
                          !is.na(.data$itemTitle)) %>%
    dplyr::select("lsn", "order", "itemTitle", "description", "link")



  #bring in procedure
  #Rename _Step, again, b/c we're not overwriting to spreadsheet
  proc <-
    googlesheets4::read_sheet(teach_it_drib, sheet = "Procedure", skip =
                                1) %>%
    dplyr::rename(Step = .data$`_Step`) %>%
    dplyr::mutate(
      lsn = as.integer(.data$lsn),
      Chunk = as.integer(.data$Chunk),
      ChunkDur = as.integer(.data$ChunkDur),
      Step = as.integer(.data$`Step`),
      lsnN = as.integer(.data$`_lsnN`),
      lsnDur = as.integer(.data$lsnDur) #we won't use this, as it's sometimes left blank. Will sum ChunkDurs
    ) %>%
    dplyr::select(1:.data$lsnDur) %>%
    dplyr::filter(!is.na(.data$lsn))


  # Check and Validate Data Import--------------------------------------------------
  checkmate::assert_data_frame(tlinks0, min.rows = 0, .var.name = "teach-it.gsheet!TeachMatLinks")
  checkmate::assert_data_frame(mlinks, min.rows = 0, .var.name = "teach-it.gsheet!Multimedia")#multimedia might be 0 rows
  checkmate::assert_data_frame(uinfo, min.rows = 0, .var.name = "teach-it.gsheet!Titles")
  checkmate::assert_data_frame(uinfo, min.rows = 0, .var.name = "teach-it.gsheet!Titles")
  checkmate::assert_data_frame(proc, min.rows = 0, .var.name = "teach-it.gsheet!Procedure")
  checkmate::assert_data_frame(lext, min.rows = 0, .var.name = "teach-it.gsheet!LsnExt")

  # Check for template text (uninitialized data) ----------------------------
  uinfo_titles_initialized <-
    !grepl("^Lesson Title", uinfo$lsnTitle[1])
  uinfo_preface_initialized <-
    !grepl("^Overall description", uinfo$unitPreface[1])

  proc_initialized <-
    !grepl("\\*\\*\\*", proc$ChunkTitle[2]) |
    nrow(proc) == 0 #template has *** in second step chunk (D4)
  proc_errors <-
    sum(!is.na(proc$`_issues`)) != 0 #FALSE if issues found
  proj_name <- basename(WD)
  if (!proc_initialized) {
    message(proj_name,
            ": Procedure not processed! Issues found...see teach-it.gsheet")
    warning(proj_name,
            ": Procedure not processed! Issues found...see teach-it.gsheet")
  }

  if (proc_errors) {
    message(proj_name, ": Procedure issues found...see teach-it.gsheet")
    warning(proj_name,
            ": Procedure issues found ! Issues found...see teach-it.gsheet")
  }


  lext_initialized <- !grepl("^URL", lext$link[1])
  mlinks_initialized <- nrow(mlinks) > 0

  # Report uninitialized data -----------------------------------------------

  if (!lext_initialized) {
    lext <- lext[0, ]
    message("No valid items found on LsnExt tab of `teach-it.gsheet`.")
  }

  if (!uinfo_titles_initialized) {
    warning(
      "Seems you haven't added Lsn Titles to `teach-it.gsheet!Titles` for `",
      fm$ShortTitle,
      "`"
    )
    #Delete filler text
    uinfo[1:nrow(uinfo), 1:5] <- NA
  }
  if (!uinfo_preface_initialized) {
    warning(
      "Either add LessonPreface or delete example text from `teach-it.gsheet!Titles` for `",
      fm$ShortTitle,
      "`"
    )
    #Delete filler text
    uinfo[1:nrow(uinfo), "LessonPreface"] <- NA
  }
  if (!proc_initialized) {
    warning(
      "Procedure not documented at `teach-it.gsheet!Procedure` for `",
      fm$ShortTitle,
      "`"
    )
  }
  if (!mlinks_initialized) {
    warning(
      "No multimedia links found at `teach-it.gsheet!Multimedia` for `",
      fm$ShortTitle,
      "`"
    )
  }else{
    cache_path <- fs::path(WD_git, "saves", "multimedia.RDS")
    test_cache_mm <- saveRDS(mlinks, cache_path) %>% catch_err()
        message(convert_T_to_check(test_cache_mm),
                " Cacheing multimedia to: ",
                cache_path)
  }


  # Assign lesson statuses --------------------------------------------------
  if (!uinfo_titles_initialized) {
    message("Not assigning lesson statuses because unit info not initialized on teach-it.gsheet")
  }
  zassign_lsn_stats(
    is_initialized = uinfo_titles_initialized,
    WD_git = WD_git,
    fm = fm,
    uinfo = uinfo
  )

  ####

  # Figure out lesson duration string ---------------------------------------
  nlessons <-
    max(1, max(c(uinfo$lsn,tlinks0$`_lsn`), na.rm = TRUE), na.rm = TRUE) #how many lessons are there in teaching mat? (1 by default)



  # Build Classroom Resources List------------------------------------------------


  #Add lesson title and preface to proc tlinks info for convenience
  if (uinfo_titles_initialized) {
    # rename Lsn folders -----------------------------------------------------
    if (rename_lessons) {
      zrename_lessons(uinfo, tmID, prompt_rename = prompt_rename)
    }

    tlinks <-
      dplyr::left_join(tlinks0, uinfo[, c("lsn",
                                          "lsnTitle",
                                          "lsnPreface",
                                          "lsnGradeVarNotes",
                                          "actTags")], by = c("_lsn" = "lsn"))


  } else{
    tlinks <-
      tlinks0
    # %>% dplyr::mutate(
    #     `_lsn` = NA,
    #     lsnTitle = NA,
    #     lsnPreface = NA,
    #     lsnGradeVarNotes = NA,
    #     actTags = NA
    #   )
  }

  # Multimedia --------------------------------------------------------------
  # Outputs to separate multimedia JSON
  # if "by" is left blank, add Galactic Polymath by default
  if (!mlinks_initialized) {
    multimedia <- list(NULL)
  } else{
    m <- mlinks
    m$by <-
      ifelse(is.na(m$by), "Galactic Polymath", m$by)
    #if byLink is blank, but by is galactic polymath, add our Youtube channel
    m$byLink <-
      ifelse(
        is.na(m$byLink) &
          !is.na(m$by),
        "https://www.youtube.com/channel/UCfyBNvN3CH4uWmwOCQVhmhg/featured",
        m$byLink
      )

    multimedia <- lapply(1:nrow(m), function(i) {
      d <- m[i,]

      mainLink <- make_yt_embed(d$mainLink) %>%
        expand_md_links(WD = WD)
      #if a drive file is supplied, change /edit? or /view? ... to /preview
      #should probably switch all this logic to a function and use urltools
      mainLink_dec <- urltools::url_parse(mainLink)

      if (mainLink_dec$domain %in% c("docs.google.com", "drive.google.com")) {
        #remove edit/
        mainLink_dec$path <-
          gsub("/edit.*|/view.*|/preview.*|/$",
               "/preview",
               mainLink_dec$path)
        #if bare url supplied (with no /), add preview suffix
        if (!grepl("/preview", mainLink_dec$path)) {
          pth <- mainLink_dec$path

          #if no slash, add one
          if (substr(pth, nchar(pth), nchar(pth)) != "/") {
            pth <- paste0(pth, "/")
          }
          #now add preview, having controlled for presence/absence of terminal /
          mainLink_dec$path <- paste0(pth, "preview")
        }

        mainLink_dec$parameter <- "rm=minimal"
        mainLink <- urltools::url_compose(mainLink_dec)

      }


      list(
        order = d$order,
        type = d$type,
        forLsn = d$forLsn,
        title = d$title,
        description = d$description,
        lessonRelevance = d$lessonRelevance,
        by = d$by,
        #if byLink left blank, but
        byLink = d$byLink,
        #Change YouTube links to be embeds & turn {filename.png} links to files found in assets/_other-media-to-publish into catalog.galacticpolymath.com links
        mainLink = mainLink,
        otherLink = d$otherLink
      )
    })
  }

  # Extract majority of Teach-It data ---------------------------------------
  #Get item links for each environment*gradeBand

  teach_mat_data <- zget_envir(tlinks, fm = fm)

  if (!proc_initialized) {
    #should change 'lessons' to something more like 'procedure'
    #output NULL structure paralleling real data
    proc_data <- list()
    proc_data$lessonDur <- NULL
    proc_data$lessons <- purrr::map(1:nlessons, \(i) {
      list(
        lsnNum = i,
        lsnTitle = paste0("Procedure not documented yet"),
        lsnDur = NULL,
        lsnPreface = NULL,
        Chunks = NULL,
        lsnExtension = NULL
      )
    })
    proc_data$vocab <- NULL
  } else{
    proc_data_test <-
      zget_procedure(
        proc = proc,
        lext = lext,
        uinfo = uinfo,
        mlinks = mlinks,
        WD_git = WD_git
      ) %>% catch_err(keep_results = TRUE)
    if (!proc_data_test$success) {
      message("FAILED to compile procedures")
      warning("FAILED to compile procedures")
      stop()
      proc_data <- NULL

    } else{
      proc_data <- proc_data_test$result

      #output gathered vocab as csv
      if (!is.null(proc_data$vocab)) {
        vocab_outfile <-
          fs::path(WD, "assets", "_other-media-to-publish", "vocab.csv")
        vocab_saved <-
          write.csv(x = proc_data$vocab,
                    file = vocab_outfile,
                    row.names = FALSE) %>% catch_err()
        if (vocab_saved) {
          message("\nVocab gathered from procedure and saved to ",
                  vocab_outfile,
                  "\n")
        } else{
          warning("Vocab was gathered from procedure, but failed to save")
        }
      }
    }

  }


  Data <- c(
    lessonPreface = uinfo$unitPreface[1],
    lessonDur = proc_data$lessonDur,
    teach_mat_data,
    lesson = list(proc_data$lessons),
    gatheredVocab = list(proc_data$vocab)
  )


  #Compile Procedure if it's been documented
  if (!proc_initialized) {
    warning("Seems you haven't documented procedure at `teach-it.gsheet!Procedure` for `")
  }


  # structure final output --------------------------------------------------
  out <-
    list(`__component` = "teaching-resources.teaching-resources",
         SectionTitle = "Teaching Materials",
         Data = Data)


  # write JSON outputs ------------------------------------------------------

  destFolder <- fs::path(WD_git, "JSONs")
  outFile <-
    fs::path(destFolder, "teaching-materials", ext = "json")

  success <- save_json(out, outFile) %>% catch_err()
  save_json(multimedia, fs::path(destFolder, "multimedia", ext = "json"))


  # return compiled output --------------------------------------------------
  message(" ", rep("-", 30))
  message(" Teaching Material Compiled:")
  # print(printToScreenTable)
  message(" JSON file saved\n @ ", outFile, "\n")
  message(" JSON file saved\n @ ",
          fs::path(destFolder, "multimedia.json"),
          "\n")
  message(" Success: ", success)
  message(" ", rep("-", 30))

}
galacticpolymath/GPpub documentation built on April 5, 2025, 6:04 p.m.