Skip to content

Commit

Permalink
version 0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
tin900 authored and cran-robot committed Jun 14, 2023
0 parents commit 26bb25e
Show file tree
Hide file tree
Showing 54 changed files with 1,993 additions and 0 deletions.
23 changes: 23 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Package: vvcanvas
Title: 'Canvas' LMS API Integration
Version: 0.0.1
Authors@R:
person("Tomer", "Iwan", , "t.iwan@vu.nl", role = c("aut", "cre", "cph"))
Description: Allow R users to interact with the 'Canvas' Learning Management System (LMS) API (see
<https://canvas.instructure.com/doc/api/all_resources.html> for details).
It provides a set of functions to access and manipulate course data, assignments, grades, users,
and other resources available through the 'Canvas' API.
URL: https://github.com/vusaverse/vvcanvas
License: MIT + file LICENSE
Encoding: UTF-8
RoxygenNote: 7.2.1
Imports: dplyr, htm2txt, httr, jsonlite, magrittr, purrr, rlang,
stringr, tidyr, utils
Suggests: knitr, rmarkdown
VignetteBuilder: knitr
NeedsCompilation: no
Packaged: 2023-06-13 17:31:42 UTC; tin900
Author: Tomer Iwan [aut, cre, cph]
Maintainer: Tomer Iwan <t.iwan@vu.nl>
Repository: CRAN
Date/Publication: 2023-06-14 08:30:06 UTC
2 changes: 2 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
YEAR: 2023
COPYRIGHT HOLDER: vvcanvas authors
53 changes: 53 additions & 0 deletions MD5
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
b36e8dcbb099071041b8613f6cbdeb96 *DESCRIPTION
c2398a2b7ea800221d87ede18097c5b6 *LICENSE
b906d3eab63d2eac69d20d36339006fb *NAMESPACE
1ffd848a562acb318b17c776243eee4a *R/authenticate.R
6b1b2cc09c3091bbbb230c4894c84eea *R/create_course_datalake.R
d765023c5dc951e91ceefd345d6e1b82 *R/download_course_file.R
d26a1b15daf6095c02b71c0bae2fa922 *R/get_all_courses.R
cd8aa2586b8b32ce602d4e3859948375 *R/get_assignment_details.R
02f1e55ba0b89f0c73b24dc61508da63 *R/get_assignment_submissions.R
bd61f231f18e52eb104989a6b90670cf *R/get_assignments.R
fb2c8813b984a489e45ade37c3a8d01b *R/get_course_announcements.R
c2570fcd902099204c453d13b48a47f8 *R/get_course_details.R
59f419c2b6abbaa562ceb2b2b691f5f4 *R/get_course_enrollments.R
4af5cc0e8913f94f3662a3bc86fbb7b9 *R/get_course_files.R
75466d4ab1d593e8297e6a136618731e *R/get_course_folders.R
d3c4c51b0e2aa418c0f7583f85d5cbb0 *R/get_course_pages.R
9b316ceaaca63d8adc63532f209f0aad *R/get_course_quizzes.R
8d8ceadbd10f41e04e27dfcad0e949de *R/get_course_sections.R
f06311c92d5df0be59ab4d09aeb03420 *R/get_course_students.R
91ec3b2a1efa75c9e78801d67d30dbbf *R/get_courses.R
dca252a56126012853c86f393454439a *R/get_discussions.R
201c16e04f1808313d8024bea53f1ef7 *R/get_module_items.R
a8401e39f00a34c2bc76d4c73f921eee *R/get_modules.R
62289c9eb3f3dc26092b9c18b95ac413 *R/get_page_content.R
b56ff2b193ecba52f9ec7f3b10cca008 *R/utils-pipe.R
df9e1bec20da0ce586a798a1aef40921 *README.md
2c841006c6b6a093aaada5e065ea2b51 *build/vignette.rds
1af298d75f70dcedd71606da80417c8f *inst/doc/getting_started.R
cf7591bbd6cd619dbba9f18781cfdef7 *inst/doc/getting_started.Rmd
d1dd8b469465638517092552cc50072b *inst/doc/getting_started.html
9c400a458efea0b5d453e2cab4ef979b *man/canvas_authenticate.Rd
7b7fc217c24be2e2232bb10322d16f76 *man/create_course_datalake.Rd
a18afa501433433e16cae61dea134bbd *man/download_course_file.Rd
9c96b216955a133fcc23840f34cb4b6d *man/get_all_courses.Rd
47d2a1841a636cf4f537ffac8f10a32e *man/get_assignment_details.Rd
de88c29eed316eb3216a4a9bc6870c8e *man/get_assignment_submissions.Rd
0c0d719b05f0764199452707a281f60a *man/get_assignments.Rd
ac859fee0b49920cdec008d45518ff81 *man/get_course_announcements.Rd
3654812e31cfb50efe99bfa897198132 *man/get_course_details.Rd
7fc56274cad9b19b9105ee8667183cdb *man/get_course_enrollments.Rd
5e9d9d82c8bad24a4b678b3a48529307 *man/get_course_files.Rd
f276bd1ff81ac6b65c5cd8987e4ff25a *man/get_course_folders.Rd
347cf3861a1306b9db8a47fb516aca3f *man/get_course_pages.Rd
9f80a4a8f5c675e22e35f98c619c5576 *man/get_course_quizzes.Rd
4ab15d0c0a8de63a805adc791970bdf7 *man/get_course_sections.Rd
1f0e8da2c839334bbc98797b219f23d5 *man/get_course_students.Rd
998d1e1cdb18262000e9091f828b36c0 *man/get_courses.Rd
2373e1e06c8cf0fbe5f7bceee0afade0 *man/get_discussions.Rd
dab5d11a742055cdcaca9a04947a734d *man/get_module_items.Rd
a31ed71c8c9f3aa463de9c30d45af681 *man/get_modules.Rd
7b72b23bb854752a5dd8d499bf912c23 *man/get_page_content.Rd
8f4aad003a999fae004ba9361f9a99d6 *man/pipe.Rd
cf7591bbd6cd619dbba9f18781cfdef7 *vignettes/getting_started.Rmd
27 changes: 27 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by roxygen2: do not edit by hand

export("%>%")
export(canvas_authenticate)
export(create_course_datalake)
export(download_course_file)
export(get_all_courses)
export(get_assignment_details)
export(get_assignment_submissions)
export(get_assignments)
export(get_course_announcements)
export(get_course_details)
export(get_course_enrollments)
export(get_course_files)
export(get_course_folders)
export(get_course_pages)
export(get_course_quizzes)
export(get_course_sections)
export(get_course_students)
export(get_courses)
export(get_discussions)
export(get_module_items)
export(get_modules)
export(get_page_content)
importFrom(magrittr,"%>%")
importFrom(rlang,.data)
importFrom(utils,download.file)
37 changes: 37 additions & 0 deletions R/authenticate.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#' Authenticate with Canvas LMS API
#'
#' Handles authentication with the Canvas LMS API using the provided API key and base URL.
#'
#' @param api_key The API key for authenticating with the Canvas LMS API.
#' @param base_url The base URL of the Canvas instance.
#'
#' @return A list containing the authenticated 'api_key' and 'base_url'.
#' @export
#' @examples
#' \dontrun{
#' # Authenticate with the Canvas LMS API
#' api_key <- "your_api_key"
#' base_url <- "https://canvas.example.com"
#' canvas <- canvas_authenticate(api_key, base_url)
#' }
canvas_authenticate <- function(api_key, base_url) {
# Create a canvas object to store the API key and base URL
canvas <- list(api_key = api_key, base_url = base_url)

# Check if the base URL ends with a trailing slash and remove it if present
if (substr(canvas$base_url, nchar(canvas$base_url), nchar(canvas$base_url)) == "/") {
canvas$base_url <- substr(canvas$base_url, 1, nchar(canvas$base_url) - 1)
}

# Verify authentication by making a test request
test_url <- paste0(canvas$base_url, "/api/v1/users/self")
response <- httr::GET(test_url, httr::add_headers(Authorization = paste("Bearer", canvas$api_key)))

# Check the response status code
if (httr::status_code(response) != 200) {
stop("Authentication failed. Please check your API key and base URL.")
}

# Return the canvas object
return(canvas)
}
105 changes: 105 additions & 0 deletions R/create_course_datalake.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#' Create a data lake for a course.
#'
#' This function retrieves data from various endpoints for a specific course in the Canvas LMS API
#' and stores the data as JSON files in a specified storage location.
#'
#' @param canvas An object containing the Canvas API key and base URL, obtained through the `canvas_authenticate` function.
#' @param course_id The ID of the course for which to create the data lake.
#' @param storage_location The path to the storage location where the data files will be saved.
#' @return NULL.
#'
#' @export
#' @note This function retrieves data from various endpoints. Access to certain endpoints may require specific roles.
create_course_datalake <- function(canvas, course_id, storage_location) {
# Check if the storage location exists and create it if not
if (!dir.exists(storage_location)) {
dir.create(storage_location, recursive = TRUE)
}

# Define the list of endpoints to retrieve data from
endpoints <- list(
"details" = "/api/v1/courses/{course_id}",
"analytics" = "/api/v1/courses/{course_id}/analytics",
"assignments" = "/api/v1/courses/{course_id}/assignments",
"assignment_groups" = "/api/v1/courses/{course_id}/assignment_groups",
"conferences" = "/api/v1/courses/{course_id}/conferences",
"discussion_topics" = "/api/v1/courses/{course_id}/discussion_topics",
"files" = "/api/v1/courses/{course_id}/files",
"folders" = "/api/v1/courses/{course_id}/folders",
"modules" = "/api/v1/courses/{course_id}/modules",
"module_items" = "/api/v1/courses/{course_id}/modules/items",
"outcomes" = "/api/v1/courses/{course_id}/outcomes",
"pages" = "/api/v1/courses/{course_id}/pages",
"quizzes" = "/api/v1/courses/{course_id}/quizzes",
"rubrics" = "/api/v1/courses/{course_id}/rubrics",
"sections" = "/api/v1/courses/{course_id}/sections",
"assignments_for_grade_export" = "/api/v1/courses/{course_id}/assignments/for_grade_export",
"enrollments" = "/api/v1/courses/{course_id}/enrollments",
"student_enrollments" = "/api/v1/courses/{course_id}/enrollments?type[]=student",
"teacher_enrollments" = "/api/v1/courses/{course_id}/enrollments?type[]=teacher",
"ta_enrollments" = "/api/v1/courses/{course_id}/enrollments?type[]=ta",
"observer_enrollments" = "/api/v1/courses/{course_id}/enrollments?type[]=observer",
"admin_enrollments" = "/api/v1/courses/{course_id}/enrollments?type[]=admin",
"collaborations" = "/api/v1/courses/{course_id}/collaborations",
"users" = "/api/v1/courses/{course_id}/users",
"course_score_and_grade_export" = "/api/v1/courses/{course_id}/score_and_grade_export",
"course_settings" = "/api/v1/courses/{course_id}/settings",
"blueprint_templates" = "/api/v1/courses/{course_id}/blueprint_templates",
"blueprint_subscriptions" = "/api/v1/courses/{course_id}/blueprint_subscriptions",
"blueprint_migrations" = "/api/v1/courses/{course_id}/blueprint_migrations",
"blueprint_import" = "/api/v1/courses/{course_id}/blueprint_import",
"blueprint_exports" = "/api/v1/courses/{course_id}/blueprint_exports",
"storage_quota_used" = "/api/v1/courses/{course_id}/storage_quota_used",
"tabs" = "/api/v1/courses/{course_id}/tabs",
"usage_rights" = "/api/v1/courses/{course_id}/usage_rights",
"account_notifications" = "/api/v1/courses/{course_id}/account_notifications",
"blueprint_restricted_attachments" = "/api/v1/courses/{course_id}/blueprint_restricted_attachments",
"usage_rights_information" = "/api/v1/courses/{course_id}/usage_rights_information",
"default_view" = "/api/v1/courses/{course_id}/default_view",
"calendar_events" = "/api/v1/courses/{course_id}/calendar_events",
"calendars" = "/api/v1/courses/{course_id}/calendars",
"appointment_groups" = "/api/v1/courses/{course_id}/appointment_groups",
"external_feeds" = "/api/v1/courses/{course_id}/external_feeds",
"rubric_associations" = "/api/v1/courses/{course_id}/rubric_associations",
"content_exports" = "/api/v1/courses/{course_id}/content_exports",
"content_imports" = "/api/v1/courses/{course_id}/content_imports",
"content_migration" = "/api/v1/courses/{course_id}/content_migrations",
"blueprint_course_associations" = "/api/v1/courses/{course_id}/blueprint_course_associations",
"blueprint_restrictions" = "/api/v1/courses/{course_id}/blueprint_restrictions",
"calendar_events_feed" = "/api/v1/courses/{course_id}/calendar_events/feed",
"calendar_event_reservations" = "/api/v1/courses/{course_id}/calendar_event_reservations",
"calendar_events_user" = "/api/v1/courses/{course_id}/calendar_events/user"
)



# Iterate through the endpoints and retrieve data
for (endpoint in names(endpoints)) {
# Construct the API endpoint URL
endpoint_url <- gsub("\\{course_id\\}", course_id, endpoints[[endpoint]])
url <- paste0(canvas$base_url, endpoint_url)

# Make the API request
response <- httr::GET(url, httr::add_headers(Authorization = paste("Bearer", canvas$api_key)))

# Check the response status code
if (httr::status_code(response) != 200) {
message(paste("Failed to retrieve data from endpoint:", endpoint), "\n")
next
}

# Parse the response as JSON
data <- httr::content(response, "text", encoding = "UTF-8") %>%
jsonlite::fromJSON(flatten = TRUE)

# Define the file path to store the data
file_path <- file.path(storage_location, paste0(endpoint, ".json"))

# Write the data to file in JSON format
jsonlite::write_json(data, file_path)

message(paste("Data from endpoint", endpoint, "saved to", file_path), "\n")
}

message("Course data lake created successfully!\n")
}
42 changes: 42 additions & 0 deletions R/download_course_file.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#' Downloads a file from a given URL.
#'
#' This function downloads a file from a specified URL and saves it locally.
#'
#' @param canvas An object containing the Canvas API key and base URL, obtained through the `canvas_authenticate` function.
#' @param file_url The URL of the file to download.
#' @param download_path The path where the file should be downloaded.
#'
#' @return The path of the downloaded file.
#' @export
#' @examples
#' \dontrun{
#' # Download a file from a given URL
#' canvas <- canvas_authenticate(api_key, base_url)
#' file_url <- "https://example.com/file.pdf"
#' download_path <- "path/to/save/file.pdf"
#' file_path <- download_course_file(canvas, file_url, download_path)
#' }
#' @importFrom utils download.file
download_course_file <- function(canvas, file_url, download_path) {
# Get the filename from the URL
response <- httr::GET(file_url)

# Extract filename including extension from the response url
filename <- stringr::str_extract(response$url, paste0("\\b\\w+\\.(?i)(pdf|txt|csv|ppt|pptx)\\b"))

# Set the path for the downloaded file
file_path <- file.path(download_path, filename)

# Download the file
download_result <- tryCatch(
{
download.file(file_url, destfile = file_path, mode = "wb")
file_path
},
error = function(e) {
stop(paste("Failed to download file from URL:", file_url))
}
)

return(download_result)
}
52 changes: 52 additions & 0 deletions R/get_all_courses.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#' Retrieves a paginated list of all courses visible in the public index.
#'
#' This function retrieves a paginated list of all courses visible in the public index
#' using the Canvas LMS API.
#' *NOTE* This function might take a while to finish.
#' @param canvas An object containing the Canvas API key and base URL, obtained through the `canvas_authenticate` function.
#' @param per_page (Optional) The number of courses to retrieve per page of results (default is 100).
#'
#' @return A data frame of courses visible in the public index.
#' @export
get_all_courses <- function(canvas, per_page = 100) {
# Initialize an empty data frame to store the courses
all_courses <- data.frame()

# Start with the first page
page <- 1

# Loop until all pages have been fetched
while (TRUE) {
# Construct the API endpoint URL for the current page
url <- paste0(canvas$base_url, "/api/v1/search/all_courses?per_page=", per_page, "&page=", page)

# Make the API request
response <- httr::GET(url, httr::add_headers(Authorization = paste("Bearer", canvas$api_key)))

# Check the response status code
if (httr::status_code(response) != 200) {
stop("Failed to retrieve all courses. Please check your authentication and API endpoint.")
}

# Parse the response as JSON
courses <- httr::content(response, "text", encoding = "UTF-8") %>%
jsonlite::fromJSON(flatten = TRUE)

# Append the courses to the accumulated data frame
all_courses <- dplyr::bind_rows(all_courses, courses)

# Print progress message
message("Fetched", nrow(courses), "courses from page", page, "\n")

# Increment the page counter
page <- page + 1

# Break the loop if there are no more courses
if (length(courses) == 0) {
break
}
}

# Return the data frame of all courses
return(all_courses)
}
35 changes: 35 additions & 0 deletions R/get_assignment_details.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#' Get Assignment Details from Canvas LMS API
#'
#' Retrieves detailed information about a specific assignment from the Canvas LMS API.
#'
#' @param canvas A list containing the 'api_key' and 'base_url' for authentication.
#' @param course_id The ID of the course in which the assignment resides.
#' @param assignment_id The ID of the assignment for which to retrieve the details.
#'
#' @return A dataframe containing the detailed information about the assignment.
#' @export
#'
get_assignment_details <- function(canvas, course_id, assignment_id) {
# Construct the API endpoint URL
url <- paste0(canvas$base_url, "/api/v1/courses/", course_id, "/assignments/", assignment_id)

# Make the API request
response <- httr::GET(url, httr::add_headers(Authorization = paste("Bearer", canvas$api_key)))

# Check the response status code
if (httr::status_code(response) != 200) {
stop("Failed to retrieve assignment details. Please check your authentication and API endpoint.")
}

# Parse the response as JSON
assignment_details <- httr::content(response, "text", encoding = "UTF-8")

# Return the assignment details as a list
return(assignment_details)
}






0 comments on commit 26bb25e

Please sign in to comment.