From 328ac9146ff371c802efaf86079fbbbaec5d47f0 Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 24 May 2024 15:39:00 -0400 Subject: [PATCH] Proactively clear old Zoom reminders (#9) * R4DS to DSLC * Refactor reminder clearing. And add separate reminder clearer --- .github/SUPPORT.md | 2 +- DESCRIPTION | 4 +- NAMESPACE | 7 +- R/bookclubcron-package.R | 1 + R/clubs.R | 2 +- R/slack.R | 227 ++++++++++++++++-- R/youtube.R | 34 +-- R/zoom.R | 57 +---- R/zzz.R | 4 +- inst/runners/clear_reminders.R | 3 + inst/setup_cron.R | 22 +- man/bookclubcron-package.Rd | 2 +- man/dot-cache_dslc_slack_channels.Rd | 18 ++ ...Rd => dot-cache_dslc_youtube_playlists.Rd} | 10 +- man/dot-cache_r4ds_slack_channels.Rd | 15 -- man/dot-check_can_upload.Rd | 2 +- man/dot-fetch_dslc_slack_channels.Rd | 18 ++ ...Rd => dot-fetch_dslc_youtube_playlists.Rd} | 10 +- man/dot-fetch_r4ds_slack_channels.Rd | 15 -- man/dslc_slack_channels.Rd | 19 ++ ...playlists.Rd => dslc_youtube_playlists.Rd} | 10 +- man/r4ds_slack_channels.Rd | 17 -- man/slack_default_token.Rd | 22 ++ man/slack_set_token.Rd | 20 ++ 24 files changed, 387 insertions(+), 154 deletions(-) create mode 100644 inst/runners/clear_reminders.R create mode 100644 man/dot-cache_dslc_slack_channels.Rd rename man/{dot-cache_r4ds_youtube_playlists.Rd => dot-cache_dslc_youtube_playlists.Rd} (61%) delete mode 100644 man/dot-cache_r4ds_slack_channels.Rd create mode 100644 man/dot-fetch_dslc_slack_channels.Rd rename man/{dot-fetch_r4ds_youtube_playlists.Rd => dot-fetch_dslc_youtube_playlists.Rd} (64%) delete mode 100644 man/dot-fetch_r4ds_slack_channels.Rd create mode 100644 man/dslc_slack_channels.Rd rename man/{r4ds_youtube_playlists.Rd => dslc_youtube_playlists.Rd} (61%) delete mode 100644 man/r4ds_slack_channels.Rd create mode 100644 man/slack_default_token.Rd create mode 100644 man/slack_set_token.Rd diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index 73d527b..de059f0 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -14,7 +14,7 @@ For additional reprex pointers, check out the [Get help!](https://www.tidyverse. Armed with your reprex, the next step is to figure out where to ask. -* If it's a question: It's best to ask on the [R4DS Online Learning Community Slack](https://r4ds.io/join). Other options include [Posit Community](https://community.rstudio.com/), and StackOverflow. There are more people there to answer questions. +* If it's a question: It's best to ask on the [Data Science Learning Community Slack](https://DSLC.io/join). Other options include [Posit Community](https://community.rstudio.com/), and StackOverflow. There are more people there to answer questions. * If it's a bug: you're in the right place, [file an issue](https://github.com/r4ds/bookclubcron/issues/new). diff --git a/DESCRIPTION b/DESCRIPTION index c2dd625..ebaf81f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: bookclubcron -Title: Automated Tasks for R4DS Book Clubs +Title: Automated Tasks for DSLC Book Clubs Version: 0.0.1 Authors@R: person("Jon", "Harmon", , "jonthegeek@gmail.com", role = c("aut", "cre"), @@ -13,10 +13,12 @@ BugReports: https://github.com/r4ds/bookclubcron/issues Imports: cli, dplyr, + fastmatch, fs, glue, googlesheets4, httr2, + keyring, lubridate, memoise, purrr, diff --git a/NAMESPACE b/NAMESPACE index 2e726ca..fd1b2d5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,10 +1,13 @@ # Generated by roxygen2: do not edit by hand +export(dslc_slack_channels) +export(dslc_youtube_playlists) export(process_youtube) export(process_zoom) -export(r4ds_slack_channels) -export(r4ds_youtube_playlists) export(reset_the) +export(slack_default_token) +export(slack_set_token) +importFrom(fastmatch,"%fin%") importFrom(rlang,"%||%") importFrom(rlang,.data) importFrom(rlang,.env) diff --git a/R/bookclubcron-package.R b/R/bookclubcron-package.R index dfac96f..c53c03b 100644 --- a/R/bookclubcron-package.R +++ b/R/bookclubcron-package.R @@ -2,6 +2,7 @@ "_PACKAGE" ## usethis namespace: start +#' @importFrom fastmatch %fin% #' @importFrom rlang %||% #' @importFrom rlang .data #' @importFrom rlang .env diff --git a/R/clubs.R b/R/clubs.R index 907034f..7fbaf70 100644 --- a/R/clubs.R +++ b/R/clubs.R @@ -6,7 +6,7 @@ # update the spreadsheet if it's wrong, so it can be right when the meeting is # posted! -r4ds_active_clubs <- function() { +dslc_active_clubs <- function() { # TODO: Load info about running clubs. Right now we only use the length, and # it isn't super important, so just return a long-enough object. return(1:50) diff --git a/R/slack.R b/R/slack.R index 79586bb..65c08c6 100644 --- a/R/slack.R +++ b/R/slack.R @@ -1,14 +1,16 @@ -#' Cache or Fetch R4DS Slack channels +#' Cache or Fetch DSLC Slack channels #' -#' Fetch public and private R4DS Slack channel information. +#' Fetch public and private DSLC Slack channel information. #' +#' @inheritParams .fetch_dslc_slack_channels #' @param refresh Get fresh data? #' -#' @inherit .fetch_r4ds_slack_channels return +#' @inherit .fetch_dslc_slack_channels return #' @export -r4ds_slack_channels <- function(refresh = FALSE) { +dslc_slack_channels <- function(refresh = FALSE, + token = slack_default_token()) { if (refresh) { - .cache_r4ds_slack_channels() + .cache_dslc_slack_channels(token) return(the$slack_channels) } @@ -16,38 +18,233 @@ r4ds_slack_channels <- function(refresh = FALSE) { rlang::env_cache( the, "slack_channels", - .fetch_r4ds_slack_channels() + .fetch_dslc_slack_channels(token) ) ) } -#' Cache R4DS Slack channels +#' Cache DSLC Slack channels #' -#' Set R4DS slack channels in the package `the` environment. +#' Set DSLC slack channels in the package `the` environment. #' -#' @return A dataframe with information about R4DS Slack channels, invisibly. +#' @inheritParams .fetch_dslc_slack_channels +#' +#' @return A dataframe with information about DSLC Slack channels, invisibly. #' @keywords internal -.cache_r4ds_slack_channels <- function() { +.cache_dslc_slack_channels <- function(token = slack_default_token()) { return( rlang::env_bind( the, - slack_channels = .fetch_r4ds_slack_channels() + slack_channels = .fetch_dslc_slack_channels(token) ) ) } -#' Fetch R4DS Slack channels +#' Fetch DSLC Slack channels +#' +#' @inheritParams slackteams::get_conversations_list #' -#' @return A dataframe with information about R4DS Slack channels. +#' @return A dataframe with information about DSLC Slack channels. #' @keywords internal -.fetch_r4ds_slack_channels <- function() { +.fetch_dslc_slack_channels <- function(token = slack_default_token()) { return( dplyr::select( slackteams::get_conversations_list( type = c("public_channel", "private_channel"), - exclude_archived = TRUE + exclude_archived = TRUE, + token = token ), "id", "name", "is_private", "created", "is_general" ) ) } + +#' Fetch a Slack token +#' +#' Fetch the Slack token using the keyring package (if available), or an +#' environment variable with the same name. +#' +#' @param key_name The name of the keyring key or the environment variable. +#' +#' @return The token value as a string, or NULL (invisibly). +#' @export +#' +#' @examples +#' token <- slack_default_token() +#' nchar(token) +slack_default_token <- function(key_name = "SLACK_API_TOKEN") { + key_value <- .keyring_try(key_name) %||% Sys.getenv(key_name) + return(invisible(key_value)) +} + +.keyring_try <- function(key_name, keyring = NULL) { + tryCatch( + keyring::key_get(key_name, keyring = keyring), + error = function(e) NULL + ) +} + +#' Set a Slack API token +#' +#' Use the keyring package to store an API key. +#' +#' @param key_name The name of the key. +#' @param keyring The name of a specific keyring, passed on to +#' `keyring::set_key` if available. +#' +#' @return The key, invisibly. +#' @export +slack_set_token <- function(key_name = "SLACK_API_TOKEN", keyring = NULL) { + rlang::check_installed("keyring", "to save the API token securely.") # nocov + keyring::key_set(key_name, prompt = "Slack API token", keyring = keyring) # nocov + return(invisible(.keyring_try(key_name, keyring = keyring))) # nocov +} + +remove_slack_reminders <- function(channel_name, + min_age_minutes = 55, + max_msgs_to_check = Inf, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + channel_id <- .slack_channel_name_to_id(channel_name, token, slack_channels) + old_reminder_messages <- .slack_reminder_messages( + channel_id, + min_age_minutes = 55, + max_msgs_to_check = max_msgs_to_check, + token = token, + slack_channels = slack_channels + ) + .delete_slack_messages(old_reminder_messages, channel_id) +} + +.slack_reminder_messages <- function(channel_id, + min_age_minutes = NULL, + max_msgs_to_check = Inf, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + channel_messages <- dslc_slack_channel_messages( + channel_id, + max_results = max_msgs_to_check, + token = token, + slack_channels = slack_channels + ) + .filter_slack_messages( + channel_messages, + user = "USLACKBOT", + text = "Join Zoom Meeting", + min_age_minutes = min_age_minutes + ) +} + +.slack_channel_name_to_id <- function(channel_name, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + channel_name <- .validate_channel_name(channel_name, token, slack_channels) + slack_channels$id[slack_channels$name == channel_name] +} + +.validate_channel_name <- function(channel_name, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + if (channel_name %in% slack_channels$name) { + return(channel_name) + } + cli::cli_abort( + "Cannot find channel {channel_name}.", + class = "bookclubcron-error-channel_name" + ) +} + +dslc_slack_channel_messages <- function(channel_id, + max_results = Inf, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + slackthreads::conversations( + channel_id, + token = token, + max_results = max_results, + limit = min(1000, max_results) + ) +} + +.filter_slack_messages <- function(channel_messages, + user = NULL, + text = NULL, + min_age_minutes = NULL) { + purrr::keep( + channel_messages, + \(x) { + (is.null(user) || x[["user"]] %fin% user) && + (is.null(text) || stringr::str_detect(x[["text"]], text)) && + (is.null(min_age_minutes) || .ts_is_older(x[["ts"]], min_age_minutes)) + } + ) +} + +.ts_is_older <- function(ts, min_age_minutes) { + .ts_age(ts) > lubridate::minutes(min_age_minutes) +} + +.ts_age <- function(ts) { + lubridate::now() - .ts_as_datetime(ts) +} + +.ts_as_datetime <- function(ts) { + lubridate::as_datetime(as.numeric(ts)) +} + +.delete_slack_message <- function(channel_id, + timestamp, + token = slack_default_token()) { + slackcalls::post_slack( + slack_method = "chat.delete", + channel = channel_id, + ts = timestamp, + token = token + ) +} + +.delete_slack_messages <- function(messages, + channel_id, + token = slack_default_token()) { + for (msg in messages) { + .delete_slack_message(channel_id, msg$ts, token = token) + } +} + +dslc_book_club_channels <- function(token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + slack_channels |> + dplyr::filter(stringr::str_starts(name, "book_club-")) |> + dplyr::pull(.data$name) +} + +remove_all_club_reminders <- function(min_age_minutes = 55, + token = slack_default_token(), + slack_channels = dslc_slack_channels( + token = token + )) { + club_channels <- dslc_book_club_channels( + token = token, + slack_channels = slack_channels + ) + for (channel_name in club_channels) { + remove_slack_reminders( + channel_name, + min_age_minutes = min_age_minutes, + token = token, + slack_channels = slack_channels + ) + } +} diff --git a/R/youtube.R b/R/youtube.R index 0c62e69..22ec385 100644 --- a/R/youtube.R +++ b/R/youtube.R @@ -1,11 +1,11 @@ #' Check YouTube quota space #' -#' Check the "dev-monitoring" R4DS Slack channel for warnings about quota usage. +#' Check the "dev-monitoring" DSLC Slack channel for warnings about quota usage. #' #' @return If there's room, `TRUE` invisibly (error otherwise). #' @keywords internal .check_can_upload <- function() { - slack_channels <- r4ds_slack_channels() + slack_channels <- dslc_slack_channels() # Check monitoring channel for quota info. monitor_channel_id <- slack_channels$id[ @@ -40,18 +40,18 @@ return(invisible(TRUE)) } -#' Cache or Fetch R4DS Slack channels +#' Cache or Fetch DSLC YouTube Playlists #' -#' Fetch public and private R4DS Slack channel information. +#' Fetch DSLC YouTube playlist information. #' -#' @inheritParams .fetch_r4ds_youtube_playlists +#' @inheritParams .fetch_dslc_youtube_playlists #' @param refresh Get fresh data? #' -#' @inherit .fetch_r4ds_youtube_playlists return +#' @inherit .fetch_dslc_youtube_playlists return #' @export -r4ds_youtube_playlists <- function(n = 50L, refresh = FALSE) { +dslc_youtube_playlists <- function(n = 50L, refresh = FALSE) { if (refresh) { - .cache_r4ds_youtube_playlists(n) + .cache_dslc_youtube_playlists(n) return(the$youtube_playlists) } @@ -59,36 +59,36 @@ r4ds_youtube_playlists <- function(n = 50L, refresh = FALSE) { rlang::env_cache( the, "youtube_playlists", - .fetch_r4ds_youtube_playlists(n) + .fetch_dslc_youtube_playlists(n) ) ) } -#' Cache R4DS YouTube playlists +#' Cache DSLC YouTube playlists #' -#' Set R4DS YouTube playlists in the package `the` environment. +#' Set DSLC YouTube playlists in the package `the` environment. #' -#' @inheritParams .fetch_r4ds_youtube_playlists +#' @inheritParams .fetch_dslc_youtube_playlists #' #' @return A character vector of playlist IDs, with titles as names, invisibly. #' @keywords internal -.cache_r4ds_youtube_playlists <- function(n) { +.cache_dslc_youtube_playlists <- function(n) { return( rlang::env_bind( the, - youtube_playlists = .fetch_r4ds_youtube_playlists(n) + youtube_playlists = .fetch_dslc_youtube_playlists(n) ) ) } -#' Fetch R4DS YouTube Playlists +#' Fetch DSLC YouTube Playlists #' #' @param n How many playlists do we need? This should ideally be equal to the #' number of active clubs. #' #' @return A character vector of playlist IDs, with titles as names. #' @keywords internal -.fetch_r4ds_youtube_playlists <- function(n) { +.fetch_dslc_youtube_playlists <- function(n) { # TODO: {youtubeR} endpoint raw_playlists <- youtubeR::yt_call_api( endpoint = "playlists", @@ -194,7 +194,7 @@ process_youtube <- function() { ) ) } - slack_channels <- r4ds_slack_channels() + slack_channels <- dslc_slack_channels() slack_msg <- glue::glue( "The most recent cohort{cohort_number} meeting: ", diff --git a/R/zoom.R b/R/zoom.R index 1568974..e1af76e 100644 --- a/R/zoom.R +++ b/R/zoom.R @@ -27,9 +27,9 @@ process_zoom <- function() { # rpkgs06, which hasn't gotten a new video since 2023-04-22; many newer # lists didn't make the cut. - # youtube_playlists <- r4ds_youtube_playlists(n + 5L) # Pad for new clubs. - youtube_playlists <- r4ds_youtube_playlists(100L) - slack_channels <- r4ds_slack_channels() + # youtube_playlists <- dslc_youtube_playlists(n + 5L) # Pad for new clubs. + youtube_playlists <- dslc_youtube_playlists(100L) + slack_channels <- dslc_slack_channels() working_video_dir <- fs::path( rappdirs::user_cache_dir("bookclubcron") @@ -119,7 +119,7 @@ process_zoom <- function() { end_time <- chat_log |> tolower() |> # Allow for a few variants of "end". - stringr::str_subset("\\s*end|finish|stop") + stringr::str_subset("\\s+end|finish|stop($|\\s)") if (length(end_time)) { # If they said "end" more than once, just use the last one. @@ -212,7 +212,7 @@ process_zoom <- function() { # Download chats to their folder. chat_dir <- fs::path_home( "Dropbox (Personal)", - "R", "R4DScommunity", "r4ds_bookclub_meetings", "Chats", + "R", "dslc-video", "chats", cohort_id ) @@ -373,10 +373,10 @@ process_zoom <- function() { title = glue::glue("BOOK: Introduction ({cohort_id} 1)"), description = glue::glue( "FACILITATOR kicks off a new book club for BOOK by AUTHORS", - "on {meeting_date}, to the R4DS {book_abbrev} Book Club.", + "on {meeting_date}, to the DSLC {book_abbrev} Book Club.", "Cohort {cohort_number}", - "\n\nRead along at BOOK_URL", - "\nJoin the conversation at r4ds.io/join!", + "\n\nRead along at https://DSLC.io/{book_abbrev}", + "\nJoin the conversation at https://DSLC.io/join!", .sep = " " ), tags = "rstats" @@ -466,46 +466,7 @@ process_zoom <- function() { .clean_zoom <- function(this_meeting, channel_name, slack_channels) { - # Delete the Zoom meeting announcement for this meeting on this day in - # Slack. - if (channel_name %in% slack_channels$name) { - channel_id <- slack_channels$id[slack_channels$name == channel_name] - channel_msgs <- slackthreads::conversations( - channel_id, - max_results = 100, - limit = 100 - ) - - zoom_reminder_msgs <- purrr::keep( - channel_msgs, - \(x) { - x[["user"]] == "USLACKBOT" & - stringr::str_detect( - x[["text"]], - "Join Zoom Meeting" - ) - } - ) - - if (length(zoom_reminder_msgs)) { - # We'll clean out ALL of the msgs, in case past ones got stuck. - for (zoom_msg in zoom_reminder_msgs) { - slackcalls::post_slack( - slack_method = "chat.delete", - channel = channel_id, - ts = zoom_msg$ts - ) - } - } - } else { - cli::cli_alert_danger( - c( - x = "{log_now()} Zoom message not deleted.", - "!" = "Cannot find channel {channel_name}.", - i = "Is the meeting name weird?" - ) - ) - } + remove_slack_reminders(channel_name, slack_channels = slack_channels) # Delete the recording for this meeting. httr2::request("https://api.zoom.us/v2/") |> diff --git a/R/zzz.R b/R/zzz.R index c85d306..2844f4b 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -6,11 +6,11 @@ # youtubeR::yt_authenticate() # I may not want to do this long-term, since n will eventually matter. - # .cache_r4ds_youtube_playlists(n = 50L) + # .cache_dslc_youtube_playlists(n = 50L) # Cache the Slack channels so we can hit them later. This will also make sure # we have Slack authentication. - # .cache_r4ds_slack_channels() + # .cache_dslc_slack_channels() # Ideally we should also do a quick zoom check here. diff --git a/inst/runners/clear_reminders.R b/inst/runners/clear_reminders.R new file mode 100644 index 0000000..455d2d0 --- /dev/null +++ b/inst/runners/clear_reminders.R @@ -0,0 +1,3 @@ +library(bookclubcron) + +remove_all_club_reminders() diff --git a/inst/setup_cron.R b/inst/setup_cron.R index 58834d3..62c0dcb 100644 --- a/inst/setup_cron.R +++ b/inst/setup_cron.R @@ -2,21 +2,37 @@ library(taskscheduleR) clubs_script <- system.file("runners", "clubs.R", package = "bookclubcron") taskscheduler_create( - taskname = "r4ds_clubs", + taskname = "dslc_clubs", rscript = clubs_script, schedule = "HOURLY", # schedule = "ONCE", starttime = "15:30", startdate = format(Sys.Date(), "%m/%d/%Y") ) -# taskscheduler_delete(taskname = "r4ds_clubs") +# taskscheduler_delete(taskname = "dslc_clubs") tasks <- taskscheduler_ls() |> tibble::as_tibble() tasks |> - dplyr::filter(TaskName == "r4ds_clubs") |> + dplyr::filter(TaskName == "dslc_clubs") |> dplyr::glimpse() |> dplyr::pull("Task To Run") + +reminder_script <- system.file( + "runners", + "clear_reminders.R", + package = "bookclubcron" +) + +taskscheduler_create( + taskname = "dslc_clear_reminders", + rscript = reminder_script, + schedule = "HOURLY", + # schedule = "ONCE", + starttime = "15:00", + startdate = format(Sys.Date(), "%m/%d/%Y") +) +# taskscheduler_delete(taskname = "dslc_clubs") diff --git a/man/bookclubcron-package.Rd b/man/bookclubcron-package.Rd index e1916fd..d1c6fd0 100644 --- a/man/bookclubcron-package.Rd +++ b/man/bookclubcron-package.Rd @@ -4,7 +4,7 @@ \name{bookclubcron-package} \alias{bookclubcron} \alias{bookclubcron-package} -\title{bookclubcron: Automated Tasks for R4DS Book Clubs} +\title{bookclubcron: Automated Tasks for DSLC Book Clubs} \description{ Several tasks need to run multiple times per day to keep book clubs running. } diff --git a/man/dot-cache_dslc_slack_channels.Rd b/man/dot-cache_dslc_slack_channels.Rd new file mode 100644 index 0000000..2eee395 --- /dev/null +++ b/man/dot-cache_dslc_slack_channels.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slack.R +\name{.cache_dslc_slack_channels} +\alias{.cache_dslc_slack_channels} +\title{Cache DSLC Slack channels} +\usage{ +.cache_dslc_slack_channels(token = slack_default_token()) +} +\arguments{ +\item{token}{character, api token issued by slack} +} +\value{ +A dataframe with information about DSLC Slack channels, invisibly. +} +\description{ +Set DSLC slack channels in the package \code{the} environment. +} +\keyword{internal} diff --git a/man/dot-cache_r4ds_youtube_playlists.Rd b/man/dot-cache_dslc_youtube_playlists.Rd similarity index 61% rename from man/dot-cache_r4ds_youtube_playlists.Rd rename to man/dot-cache_dslc_youtube_playlists.Rd index 27ec166..d276748 100644 --- a/man/dot-cache_r4ds_youtube_playlists.Rd +++ b/man/dot-cache_dslc_youtube_playlists.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/youtube.R -\name{.cache_r4ds_youtube_playlists} -\alias{.cache_r4ds_youtube_playlists} -\title{Cache R4DS YouTube playlists} +\name{.cache_dslc_youtube_playlists} +\alias{.cache_dslc_youtube_playlists} +\title{Cache DSLC YouTube playlists} \usage{ -.cache_r4ds_youtube_playlists(n) +.cache_dslc_youtube_playlists(n) } \arguments{ \item{n}{How many playlists do we need? This should ideally be equal to the @@ -14,6 +14,6 @@ number of active clubs.} A character vector of playlist IDs, with titles as names, invisibly. } \description{ -Set R4DS YouTube playlists in the package \code{the} environment. +Set DSLC YouTube playlists in the package \code{the} environment. } \keyword{internal} diff --git a/man/dot-cache_r4ds_slack_channels.Rd b/man/dot-cache_r4ds_slack_channels.Rd deleted file mode 100644 index 936648e..0000000 --- a/man/dot-cache_r4ds_slack_channels.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/slack.R -\name{.cache_r4ds_slack_channels} -\alias{.cache_r4ds_slack_channels} -\title{Cache R4DS Slack channels} -\usage{ -.cache_r4ds_slack_channels() -} -\value{ -A dataframe with information about R4DS Slack channels, invisibly. -} -\description{ -Set R4DS slack channels in the package \code{the} environment. -} -\keyword{internal} diff --git a/man/dot-check_can_upload.Rd b/man/dot-check_can_upload.Rd index 3348977..3d01d17 100644 --- a/man/dot-check_can_upload.Rd +++ b/man/dot-check_can_upload.Rd @@ -10,6 +10,6 @@ If there's room, \code{TRUE} invisibly (error otherwise). } \description{ -Check the "dev-monitoring" R4DS Slack channel for warnings about quota usage. +Check the "dev-monitoring" DSLC Slack channel for warnings about quota usage. } \keyword{internal} diff --git a/man/dot-fetch_dslc_slack_channels.Rd b/man/dot-fetch_dslc_slack_channels.Rd new file mode 100644 index 0000000..7f0d9f9 --- /dev/null +++ b/man/dot-fetch_dslc_slack_channels.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slack.R +\name{.fetch_dslc_slack_channels} +\alias{.fetch_dslc_slack_channels} +\title{Fetch DSLC Slack channels} +\usage{ +.fetch_dslc_slack_channels(token = slack_default_token()) +} +\arguments{ +\item{token}{character, api token issued by slack} +} +\value{ +A dataframe with information about DSLC Slack channels. +} +\description{ +Fetch DSLC Slack channels +} +\keyword{internal} diff --git a/man/dot-fetch_r4ds_youtube_playlists.Rd b/man/dot-fetch_dslc_youtube_playlists.Rd similarity index 64% rename from man/dot-fetch_r4ds_youtube_playlists.Rd rename to man/dot-fetch_dslc_youtube_playlists.Rd index e3d7f4e..f5f99a9 100644 --- a/man/dot-fetch_r4ds_youtube_playlists.Rd +++ b/man/dot-fetch_dslc_youtube_playlists.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/youtube.R -\name{.fetch_r4ds_youtube_playlists} -\alias{.fetch_r4ds_youtube_playlists} -\title{Fetch R4DS YouTube Playlists} +\name{.fetch_dslc_youtube_playlists} +\alias{.fetch_dslc_youtube_playlists} +\title{Fetch DSLC YouTube Playlists} \usage{ -.fetch_r4ds_youtube_playlists(n) +.fetch_dslc_youtube_playlists(n) } \arguments{ \item{n}{How many playlists do we need? This should ideally be equal to the @@ -14,6 +14,6 @@ number of active clubs.} A character vector of playlist IDs, with titles as names. } \description{ -Fetch R4DS YouTube Playlists +Fetch DSLC YouTube Playlists } \keyword{internal} diff --git a/man/dot-fetch_r4ds_slack_channels.Rd b/man/dot-fetch_r4ds_slack_channels.Rd deleted file mode 100644 index a4bd044..0000000 --- a/man/dot-fetch_r4ds_slack_channels.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/slack.R -\name{.fetch_r4ds_slack_channels} -\alias{.fetch_r4ds_slack_channels} -\title{Fetch R4DS Slack channels} -\usage{ -.fetch_r4ds_slack_channels() -} -\value{ -A dataframe with information about R4DS Slack channels. -} -\description{ -Fetch R4DS Slack channels -} -\keyword{internal} diff --git a/man/dslc_slack_channels.Rd b/man/dslc_slack_channels.Rd new file mode 100644 index 0000000..16eb927 --- /dev/null +++ b/man/dslc_slack_channels.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slack.R +\name{dslc_slack_channels} +\alias{dslc_slack_channels} +\title{Cache or Fetch DSLC Slack channels} +\usage{ +dslc_slack_channels(refresh = FALSE, token = slack_default_token()) +} +\arguments{ +\item{refresh}{Get fresh data?} + +\item{token}{character, api token issued by slack} +} +\value{ +A dataframe with information about DSLC Slack channels. +} +\description{ +Fetch public and private DSLC Slack channel information. +} diff --git a/man/r4ds_youtube_playlists.Rd b/man/dslc_youtube_playlists.Rd similarity index 61% rename from man/r4ds_youtube_playlists.Rd rename to man/dslc_youtube_playlists.Rd index d56fcfa..5d2a8a4 100644 --- a/man/r4ds_youtube_playlists.Rd +++ b/man/dslc_youtube_playlists.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/youtube.R -\name{r4ds_youtube_playlists} -\alias{r4ds_youtube_playlists} -\title{Cache or Fetch R4DS Slack channels} +\name{dslc_youtube_playlists} +\alias{dslc_youtube_playlists} +\title{Cache or Fetch DSLC YouTube Playlists} \usage{ -r4ds_youtube_playlists(n = 50L, refresh = FALSE) +dslc_youtube_playlists(n = 50L, refresh = FALSE) } \arguments{ \item{n}{How many playlists do we need? This should ideally be equal to the @@ -16,5 +16,5 @@ number of active clubs.} A character vector of playlist IDs, with titles as names. } \description{ -Fetch public and private R4DS Slack channel information. +Fetch DSLC YouTube playlist information. } diff --git a/man/r4ds_slack_channels.Rd b/man/r4ds_slack_channels.Rd deleted file mode 100644 index 5a9cc73..0000000 --- a/man/r4ds_slack_channels.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/slack.R -\name{r4ds_slack_channels} -\alias{r4ds_slack_channels} -\title{Cache or Fetch R4DS Slack channels} -\usage{ -r4ds_slack_channels(refresh = FALSE) -} -\arguments{ -\item{refresh}{Get fresh data?} -} -\value{ -A dataframe with information about R4DS Slack channels. -} -\description{ -Fetch public and private R4DS Slack channel information. -} diff --git a/man/slack_default_token.Rd b/man/slack_default_token.Rd new file mode 100644 index 0000000..1822d3e --- /dev/null +++ b/man/slack_default_token.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slack.R +\name{slack_default_token} +\alias{slack_default_token} +\title{Fetch a Slack token} +\usage{ +slack_default_token(key_name = "SLACK_API_TOKEN") +} +\arguments{ +\item{key_name}{The name of the keyring key or the environment variable.} +} +\value{ +The token value as a string, or NULL (invisibly). +} +\description{ +Fetch the Slack token using the keyring package (if available), or an +environment variable with the same name. +} +\examples{ +token <- slack_default_token() +nchar(token) +} diff --git a/man/slack_set_token.Rd b/man/slack_set_token.Rd new file mode 100644 index 0000000..e903558 --- /dev/null +++ b/man/slack_set_token.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slack.R +\name{slack_set_token} +\alias{slack_set_token} +\title{Set a Slack API token} +\usage{ +slack_set_token(key_name = "SLACK_API_TOKEN", keyring = NULL) +} +\arguments{ +\item{key_name}{The name of the key.} + +\item{keyring}{The name of a specific keyring, passed on to +\code{keyring::set_key} if available.} +} +\value{ +The key, invisibly. +} +\description{ +Use the keyring package to store an API key. +}