Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export(get_assignment_data)
export(get_assignment_details)
export(get_assignment_groups)
export(get_assignment_submissions)
export(get_assignment_submissions_new)
export(get_course_gradebook)
export(get_quiz_submissions)
export(get_submissions)
export(get_assignments)
export(get_calendar_events)
export(get_course_announcements)
Expand Down
46 changes: 25 additions & 21 deletions R/get_assignment_submissions.R
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
#' Lists assignment submissions for a course.
#'
#' This function retrieves a list of assignment submissions for a specific course in the Canvas LMS API.
#' If an assignment_id is provided, it will use the specific assignment endpoint. Otherwise, it will
#' attempt to get all submissions using the students/submissions endpoint, which may not be available
#' in all Canvas systems.
#'
#' @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 list assignment submissions.
#' @param assignment_id (Optional) The ID of a specific assignment for which to list submissions.
#' @param assignment_id (Optional) The ID of a specific assignment for which to list submissions. If provided, uses the more reliable assignment-specific endpoint.
#' @param per_page (Optional) The number of submissions to retrieve per page of results (default is 100).
#'
#' @return A data frame of assignment submissions for the specified course and assignment.
#' @export
get_assignment_submissions <- function(canvas, course_id, assignment_id = NULL, per_page = 100) {
# Construct the API endpoint URL
url <- paste0(canvas$base_url, "/api/v1/courses/", course_id, "/students/submissions?per_page=", per_page)

# Append the assignment_id if provided
# If assignment_id is provided, use the specific assignment endpoint
if (!is.null(assignment_id)) {
url <- paste0(url, "&assignment_id=", assignment_id)
}

# Make the API request
response <- httr::GET(url, httr::add_headers(Authorization = paste("Bearer", canvas$api_key)))
# Use the new get_submissions function for specific assignment
return(get_submissions(canvas, course_id, "assignments", assignment_id, per_page))
} else {
# For getting all submissions, try the students/submissions endpoint first
# and fall back to iterating through assignments if it fails
url <- paste0(canvas$base_url, "/api/v1/courses/", course_id, "/students/submissions?per_page=", per_page)

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

# Use pagination helper to get all pages
responses <- paginate(response, canvas$api_key)
# Use pagination helper to get all pages
responses <- paginate(response, canvas$api_key)

# Parse and combine all results
submissions_list <- lapply(responses, function(resp) {
httr::content(resp, "text", encoding = "UTF-8") %>%
jsonlite::fromJSON(flatten = TRUE) %>%
as.data.frame()
})
submissions <- dplyr::bind_rows(submissions_list)
# Parse and combine all results
submissions_list <- lapply(responses, function(resp) {
httr::content(resp, "text", encoding = "UTF-8") %>%
jsonlite::fromJSON(flatten = TRUE) %>%
as.data.frame()
})
submissions <- dplyr::bind_rows(submissions_list)

# Return the data frame of submissions
return(submissions)
# Return the data frame of submissions
return(submissions)
}
98 changes: 98 additions & 0 deletions R/get_course_gradebook.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#' Get course gradebook with all assignment and quiz submissions
#'
#' This function retrieves all assignment and quiz submissions for a course and combines them
#' into a single data frame. This is inspired by Jon Vik's work and provides a comprehensive
#' view of all student submissions in a course.
#'
#' @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 retrieve all submissions.
#' @param per_page (Optional) The number of submissions to retrieve per page of results (default is 100).
#' @param include_quizzes (Optional) Whether to include quiz submissions (default is TRUE).
#' @param include_assignments (Optional) Whether to include assignment submissions (default is TRUE).
#'
#' @return A data frame containing all submissions (assignments and quizzes) for the specified course.
#' @export
#'
get_course_gradebook <- function(canvas, course_id, per_page = 100, include_quizzes = TRUE, include_assignments = TRUE) {
gradebook_data <- list()

# Get assignments and their submissions
if (include_assignments) {
tryCatch({
assignments <- get_assignments(canvas, course_id)

if (nrow(assignments) > 0) {
assignment_submissions <- list()

for (i in 1:nrow(assignments)) {
assignment_id <- assignments$id[i]
assignment_name <- assignments$name[i]

tryCatch({
submissions <- get_submissions(canvas, course_id, "assignments", assignment_id, per_page)

if (length(submissions) > 0 && nrow(submissions) > 0) {
submissions$assignment_name <- assignment_name
submissions$assignment_id <- assignment_id
submissions$submission_type <- "assignment"
assignment_submissions[[as.character(assignment_id)]] <- submissions
}
}, error = function(e) {
message("Warning: Failed to get submissions for assignment ", assignment_id, ": ", e$message)
})
}

if (length(assignment_submissions) > 0) {
gradebook_data$assignments <- do.call(rbind, assignment_submissions)
}
}
}, error = function(e) {
message("Warning: Failed to get assignments: ", e$message)
})
}

# Get quizzes and their submissions
if (include_quizzes) {
tryCatch({
quizzes <- get_course_quizzes(canvas, course_id, per_page)

if (nrow(quizzes) > 0) {
quiz_submissions <- list()

for (i in 1:nrow(quizzes)) {
quiz_id <- quizzes$id[i]
quiz_name <- quizzes$title[i]

tryCatch({
submissions <- get_submissions(canvas, course_id, "quizzes", quiz_id, per_page)

if (length(submissions) > 0 && nrow(submissions) > 0) {
submissions$quiz_name <- quiz_name
submissions$quiz_id <- quiz_id
submissions$submission_type <- "quiz"
quiz_submissions[[as.character(quiz_id)]] <- submissions
}
}, error = function(e) {
message("Warning: Failed to get submissions for quiz ", quiz_id, ": ", e$message)
})
}

if (length(quiz_submissions) > 0) {
gradebook_data$quizzes <- do.call(rbind, quiz_submissions)
}
}
}, error = function(e) {
message("Warning: Failed to get quizzes: ", e$message)
})
}

# Combine all submissions
if (length(gradebook_data) > 0) {
combined_data <- do.call(rbind, gradebook_data)
combined_data$course_id <- course_id
return(combined_data)
} else {
message("No submissions found for course ", course_id)
return(data.frame())
}
}
33 changes: 33 additions & 0 deletions R/get_quiz_submissions.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#' Get assignment submissions
#'
#' This function retrieves submissions for a specific assignment from the Canvas LMS API.
#' This is a convenience wrapper around get_submissions() for assignments.
#'
#' @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 retrieve assignment submissions.
#' @param assignment_id The ID of the assignment for which to retrieve submissions.
#' @param per_page (Optional) The number of submissions to retrieve per page of results (default is 100).
#'
#' @return A data frame of submissions for the specified assignment.
#' @export
#'
get_assignment_submissions_new <- function(canvas, course_id, assignment_id, per_page = 100) {
return(get_submissions(canvas, course_id, "assignments", assignment_id, per_page))
}

#' Get quiz submissions
#'
#' This function retrieves submissions for a specific quiz from the Canvas LMS API.
#' This is a convenience wrapper around get_submissions() for quizzes.
#'
#' @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 retrieve quiz submissions.
#' @param quiz_id The ID of the quiz for which to retrieve submissions.
#' @param per_page (Optional) The number of submissions to retrieve per page of results (default is 100).
#'
#' @return A data frame of submissions for the specified quiz.
#' @export
#'
get_quiz_submissions <- function(canvas, course_id, quiz_id, per_page = 100) {
return(get_submissions(canvas, course_id, "quizzes", quiz_id, per_page))
}
59 changes: 59 additions & 0 deletions R/get_submissions.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#' Get submissions for assignments or quizzes
#'
#' This function retrieves submissions for assignments or quizzes from a specific course in the Canvas LMS API.
#' It can handle both assignment submissions and quiz submissions using the correct API endpoints.
#'
#' @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 retrieve submissions.
#' @param type The type of submission to retrieve. Must be either "assignments" or "quizzes".
#' @param id The ID of the assignment or quiz for which to retrieve submissions.
#' @param per_page (Optional) The number of submissions to retrieve per page of results (default is 100).
#'
#' @return A data frame of submissions for the specified assignment or quiz.
#' @export
#'
get_submissions <- function(canvas, course_id, type, id, per_page = 100) {
# Validate the type parameter
if (!type %in% c("quizzes", "assignments")) {
stop("type must be 'quizzes' or 'assignments'")
}

# Construct the API endpoint URL
url <- paste0(canvas$base_url, "/api/v1/courses/", course_id, "/",
type, "/", id, "/submissions?per_page=", per_page)

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

# Use pagination helper to get all pages
responses <- paginate(response, canvas$api_key)

# Parse and combine all results
submissions_list <- lapply(responses, function(resp) {
content_text <- httr::content(resp, "text", encoding = "UTF-8")

if (type == "quizzes") {
# For quizzes, the response structure is different - need to access the first element
submissions <- jsonlite::fromJSON(content_text, flatten = TRUE)
if (is.list(submissions) && length(submissions) > 0) {
submissions <- submissions[[1]]
}
} else {
# For assignments, parse normally
submissions <- jsonlite::fromJSON(content_text, flatten = TRUE)
}

# Convert to data frame if not already
if (length(submissions) > 0 && !is.data.frame(submissions)) {
submissions <- as.data.frame(submissions)
}

return(submissions)
})

# Combine all submissions
submissions <- dplyr::bind_rows(submissions_list)

# Return the submissions data
return(submissions)
}