Giter Site home page Giter Site logo

rcanvas's Introduction

Description

rcanvas is a bouquet of functions to query your institution’s instance of the Canvas LMS.

Installation

rcanvas is not on CRAN, but can be installed via:

devtools::install_github("daranzolin/rcanvas")
library(rcanvas)

Setup

Some prep work is required before use. You must first safely stash your Canvas API token into your operating system’s keyring. This only needs to be done once.

To obtain the Canvas API token follow this trail in Canvas:

Canvas -> Account -> Settings -> Approved Integrations -> Add new token

You then need to run the following once in the R console:

set_canvas_token("YOUR_TOKEN_HERE")

Do not save your token or the code above in an .R file because it could compromise the security of your token.

Each time you run load the rcanvas library you need to set your domain like this:

set_canvas_domain("https://canvas.yourdomain.edu")

Functions

The following functions are implemented:

  • add_enrollments: Enroll users into a course (or multiple courses)
  • add_group_users: Add users to designated groups
  • add_groups: Create groups
  • comment_submission: comment on submitted content
  • create_course_folder: create a folder within a course
  • create_canvas_course: create a new course
  • create_course_content_migration: migrate content from one course to another
  • create_course_assignment: create an assignment within a course
  • get_announcements: Get announcements for a course
  • get_course_analytics_data: Get course analytics data for a course
  • get_course_gradebook: Get the gradebook for a course
  • get_course_items: Get various course items, e.g. files, modules, pages, quizzes, etc.
  • get_course_list: List the courses you have permission to view
  • get_course_user_groups: Get users in a course and their group
  • get_discussion_id: Get the id for a specified discussion
  • get_discussions_context: Get the context for a specified discussion
  • get_group_categories: Get the categories for a specified group
  • get_group_category: Get a single group category
  • get_group_users: Get users which belong to a group
  • get_groups_context: Get the list of active groups in the given context that are visible to the user
  • get_groups_self: Get the groups which the current user (you) belongs to
  • get_submission_single: Get a single submission
  • get_submissions: Get submissions for a given course and assignment
  • get_user_items: Get various user items, e.g. missing submissions, page_views, details, etc.
  • grade_submission: Grade a submission
  • search_courses: Search all public courses
  • update_discussion_id: Update a discussion by ID
  • upload_course_file: Upload a file to a course

Usage

### Get all courses:
get_course_list()
get_course_list(include = c("teachers", "total_students"))

### Get course analytics data:
get_course_analytics_data(course_id = 20, type = "activity")

### Get course items:
get_course_items(course_id = 20, item = "users", include = "email")

### Get user items
get_user_items(user_id = 365, item = "details")
get_user_items(365, "missing_submissions")

### Get a course gradebook
get_course_gradebook(course_id = 20)

### Get submissions
get_submissions(course_id = 27, type = "assignments", type_id = 2248)
get_submissions(27, "quizzes", 168)

### Comment and grade submnissions
comment_submission(course_id = 27, assignment_id = 2248, 
                   user_id = 4227, comm = "Test comment!")
grade_submission(course_id = 27, assignment_id = 2248, 
                   user_id = 4227, grade = 95)

### Get announcements and discussions
get_announcements(course_id = 27) 
get_announcements(course_id = 27, start_date = "2017-02-01") 
get_discussions_context(4371405, object_type = "courses")

Future Work

  • Additional functions
  • More precise querying
  • More tests
  • Vignette

rcanvas's People

Contributors

bbbruce avatar daranzolin avatar dhicks avatar fsolt avatar hathawayj avatar jonovik avatar lucymcgowan avatar pachadotdev avatar scottkosty avatar stillmatic avatar ucscout avatar vanatteveldt avatar wsphd avatar yasshin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rcanvas's Issues

get_submission double counts

manually stepping through the code, i have the following for other_pages:

> other_pages
[1] "https://canvas.upenn.edu/api/v1/courses/XXX/assignments/YYY/submissions?page=1&per_page=100>"

this returns the same as the first step through; probably because it's page 1. maybe for your canvas installation other_pages returns nothing? trying this again with an assignment where 143 submissions were received, the get_submissions returns 243 entries. so it appears that the first page is always being double counted.

couple possible fixes:

  1. change other_pages logic to > 1
  2. check and only return unique values at the end

if your canvas installation's behavior is to not return the first page in 'other pages' then we should use approach 2. if you can replicate my error, we should use approach 1.

pagination on get_course_analytics_data

Might you have any ideas how to handle pagination issues when I use get_course_analytics_data.
I have in one course approx 1800 students, and the report stops at 100.

science <- get_course_analytics_data(course_id = 79909, type = "student_summaries"). I am looking to get a list of page viws and participation per student on this course.

I know this package has a life of its own even if the original brilliant creator moved on...with his life...so I am hoping for a miracle...
Any ideas on how to handle this? thank you...

create_course_assignment() returns error

New rcanvas user. The library works well to get gradebooks. However, I encountered an error trying to create assignments.

rcanvas::create_course_assignment() returns the following error:

Error in canvas_query(url, args, "POST") : Unprocessable Entity (WebDAV; RFC 4918) (HTTP 422).

Not sure if this is related to the canvas_url() changes mentioned in other issues.

Download Page content

Hi David,

I was wondering if there is a GET command for actually fetching the contents (body) of existing pages on Canvas LMS using their API. I have looked around a lot but cannot find it. Do you have any suggestions.

I'm a relative beginner with API's

Hope to hear from you.

Kind regards,

Silvester

Push Material

@daranzolin thanks for starting this package. We may be moving to canvas next fall and I would like to figure out a nice R centric way to build a Canvas course. I haven't looked at the API yet. If the possibility is there, I would love to help you build out the tools to push items into a Canvas course.

What are your thoughts?

Error when using get_course_gradebook

I'm receiving this error when using get_course_gradebook.

Error: by can't contain join column user_id which is missing from LHS

It appears to be in this sequence.

gradebook <- purrr::map_df(seq_len(n_pages), function(page) {
submissions <- purrr::pmap_dfr(list(course_id, course_assignments$id, page),
get_assignment_submissions)
gradebook_page <- dplyr::left_join(submissions, students, by = "user_id") %>%
dplyr::left_join(course_assignments %>%
dplyr::select(id, assignment_name = name),
by = c("assignment_id" = "id"))
return(gradebook_page)

get_course_list() gives curl error

When I run

set_canvas_domain("http://canvas.smcvt.edu")
get_course_list()

I get the following error:

Error: lexical error: invalid char in json text.
                                       <!DOCTYPE html PUBLIC "-//W3C//
                     (right here) ------^

Sorry for editing this so many times. I had the wrong information.

View discussion thread comments

Any interest in a contributed function that queries discussion threads to obtain all responses and they're author, e.g. get the full topic?

remove_html_tags <- function(x) {
  gsub("<.*?>", "", x)
}

get_discussion_thread = function (discussion_id, object_id, object_type = "courses")  
{
  stopifnot(object_type %in% c("courses", "groups"))
  url <- paste0(rcanvas:::canvas_url(), paste(object_type, object_id, 
                                    "discussion_topics", discussion_id, "view", sep = "/"))
  args <- list(per_page = 100)
  include <- rcanvas:::iter_args_list(NULL, "include[]")
  args <- c(args, include)

  # Workaround for process_request issue.
  resp <- rcanvas:::canvas_query(url, args, "GET")
  resp = rcanvas:::paginate(resp) %>% purrr::map(httr::content, "text") %>% 
    purrr::map(jsonlite::fromJSON, flatten = TRUE)
  
  # Merge two responses together
  msg_data = dplyr::inner_join(resp[[1]]$view, resp[[1]]$participants, by = c("user_id" = "id"))

  # Remove html formatting for text
  msg_data$message = remove_html_tags(msg_data$message)
  
  # Release discussion thread information
  msg_data
}

get_course_gradebook error

Hi,

first of all, love the work, and with this API we could manage to build a Shiny board to have an overview of our whole curriculum.

However I now run into an error with the get_course_gradebook()

get_course_gradebook(10633)
mutate_() is deprecated as of dplyr 0.7.0.
Please use mutate() instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call lifecycle::last_warnings() to see where this warning was generated.Error in UseMethod("mutate_") :
no applicable method for 'mutate_' applied to an object of class "list"

I could create an instance where i still have dplyr 0.7.0, though would it be possible to have this as a fix?

delete_wpage() fails with "object of type 'closure' is not subsettable"

delete_wpage simply does not work.

> delete_wpage(123, "test-page")
Error in x[which(ind)] : object of type 'closure' is not subsettable

The problem is that delete_wpage() has no argument called args, yet tries to pass one to canvas_query:

delete_wpage <- function(course_id, page_url){
# DELETE /api/v1/courses/:course_id/pages/:url
url <- paste0(canvas_url(), file.path("courses", course_id, "pages", page_url))
resp <- canvas_query(url, args, "DELETE")

So base::args gets passed instead, which fails when canvas_query() tries to

args = sc(args)

The fix is to simply drop the unneeded args argument.
However, the current canvas_query requires it:

function(urlx, args, type = "GET")

So if delete_wpage were to just call canvas_query(url, "DELETE"), "DELETE" would become the args argument, which is also a bug.
Things seem to work if I set args = NULL as default in canvas_query.

(It would be nice to have unit tests for this, but it's tricky because that would require a test Canvas to be available.)

uploading files no longer working

Thanks for this fantastic package, I really hope you are able to recruit a new maintainer for this! I am not sure if this is an easy fix or not, but when I try to upload files I am getting the following error:

Error in curl::curl_fetch_memory(url, handle = handle) : HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)

Is that due to an API change at canvas you think?

Uploading exams into Canvas

Hi David,
I saw your rcanvas package, it looks great! Does it also allow for going the opposite way, uploading stuff into canvas? I am a contributor to the exams package, and am exploring how exams may be automatically generated for Canvas.

http://www.r-exams.org

Uploading an exam into Canvas from R would mean a great feature to people using the package.

get_discussion_id() errors due to row combine procedure

While attempting to retrieve discussion components with get_discussion_id(), I'm receiving an error of:

get_discussion_id(discussion_id, object_id)
Error: Argument 5 is a list, must contain atomic vectors

The API call issues is found under get a single topic with structure:

/api/v1/groups/:group_id/discussion_topics/:topic_id

The error is being triggered inside rcanvas:::process_response()

Specifically, when it attempts to bind multiple data frames together, e.g.

df <- tryCatch({
df %>% purrr::map_df(purrr::flatten_df)
},
error = function(e) {
df %>% dplyr::bind_rows()
}
)

grade_submission 404 error

I've been successfully using rcanvas to download grades. But I am running into a problem when I try to submit a grade using grade_submission.

Here's an example.

grade_submission(course_id = 8652, assignment_id = 17499179, user_id = 1888, grade = 70.7)
Error in canvas_query(url, args, "PUT") : Not Found (HTTP 404).

I'm not sure what that error might mean. Any ideas?

checks

Hi
I'm running a series of manual tests because I need to import a lot of files from canvas.
Do you have any urgent issues to fix in the package?

pages body

get_course_item(courseid,'pages') does not bring back the body field. How can I get the html code from the page?

create_course_assigment() returns "Bad Request" error

Thanks for this great package! I'm a new user, so I might have just used the function incorrectly. Note that get_course_list() works well, so I think I have things set up correctly.

Here was my call to create_course_assigment():

> desc_ <- "HMC 8th edition exercises: 1.2.1, 1.2.2, 1.2.4, 1.2.6, 1.2.7, 1.2.8, 1.2.9, 1.2.14. 1.3.10, 1.3.12, 1.3.15, 1.3.21. If you have the 7th edition, do these exercises instead: 1.2.1, 1.2.2, 1.2.4, 1.2.8, 1.2.9, 1.2.10, 1.2.11, 1.2.16, 1.3.10, 13.12, 1.3.15, 1.3.20."
> create_course_assigment(course_id = 357998, name = "PS1",
+                          # change if online assignment
+                          submission_types = "on_paper",
+                          points_possible = 100,
+                          due_at = "2018-09-10T16:05",
+                          description = desc_,
+ )
Error in canvas_query(url, args, "POST") : Bad Request (HTTP 400).

Can you reproduce?

error in get_course_list in course-data.R

There is a missing assignment to dat before returning dat as a value.
The code should be:
get_course_list <- function(user_id = NULL, include = NULL) {
if (!is.null(user_id)) {
url <- paste0(canvas_url(), paste("users", user_id, "courses", sep = "/"))
} else {
url <- paste0(canvas_url(), "courses")
}
args <- list(access_token = check_token(),
per_page = 100,
user_id = user_id)
include <- iter_args_list(include, "include[]")
args <- c(args, include)
dat <- process_response(url, args) # there must be an assignment of the returned data frame to dat
return(dat)
}

create_wpage() gives HTTP error 414 if wiki_page[body] is long.

create_wpage() with more than about 8000 characters in wiki_page[body] fails with Request-URI Too Long (HTTP 414).

Usually, this error code means we used GET when we meant POST, but rcanvas::create_wpage uses rcanvas:::canvas_query(type = "POST") which in turn uses httr::POST, which I would expect to do the right thing.

As specified by the Canvas Live API
(scroll down to Pages and look for POST /v1/courses/{course_id}/pages),
canvas_query does not use the body= argument to httr::POST; instead, the page body is passed as wiki_page[body].

Here's a small reproducible example illustrating the issue; it would be interesting to test on other people's Canvases.
With a wiki_page[body] of 4 characters it works fine, and with 9000 characters (over the usual limit of 8192 bytes) it causes a HTTP 414 error.
Curiously, it runs without error in the Live API for my university's Canvas site, creating the page as expected.

library(tidyverse)
library(rcanvas)

body_size <- 4
YOUR_COURSE_TITLE <- "<insert your course title here>"
course_id <- get_course_list() %>% filter(name %>% str_detect(YOUR_COURSE_TITLE)) %>% pull(id)
title <- "Test Request-URI Too Long"
body <- paste(rep("x", body_size), collapse = "")
create_wpage(course_id, title, body)

This succeeds if body_size = 4.
We can see that the response object has a long url that contains the wiki_page[body].
(This is also the case when I test using the Live API.)

Page 'Test Request-URI Too Long' created
Response [https://abcd.instructure.com/api/v1/courses/1234/pages?wiki_page%5Btitle%5D=Test%20Request-URI%20Too%20Long&wiki_page%5Bbody%5D=xxxx&wiki_page%5Bediting_roles%5D=teachers&wiki_page%5Bnotify_of_update%5D=FALSE&wiki_page%5Bpublished%5D=FALSE&wiki_page%5Bfront_page%5D=FALSE]
  Date: 2019-08-19 04:43
  Status: 200
  Content-Type: application/json; charset=utf-8
  Size: 793 B

But it fails if body_size = 9000:

Error in canvas_query(url, args, "POST") : 
Request-URI Too Long (HTTP 414).
> devtools::session_info()
Session info ---------------------------------------------------------------------------------------------------------
 setting  value                       
 version  R version 3.6.1 (2019-07-05)
 system   x86_64, mingw32             
 ui       RStudio (1.2.1335)          
 language (EN)                        
 collate  English_United States.1252  
 tz       Europe/Berlin               
 date     2019-08-19                  

Packages -------------------------------------------------------------------------------------------------------------
 package   * version    date       source                            
 base      * 3.6.1      2019-07-05 local                             
 compiler    3.6.1      2019-07-05 local                             
 datasets  * 3.6.1      2019-07-05 local                             
 devtools    1.13.6     2018-06-27 CRAN (R 3.5.1)                    
 digest      0.6.15     2018-01-28 CRAN (R 3.5.1)                    
 graphics  * 3.6.1      2019-07-05 local                             
 grDevices * 3.6.1      2019-07-05 local                             
 magrittr    1.5        2014-11-22 CRAN (R 3.5.1)                    
 memoise     1.1.0      2017-04-21 CRAN (R 3.5.1)                    
 methods   * 3.6.1      2019-07-05 local                             
 rcanvas   * 0.0.0.9001 2019-08-14 local (daranzolin/rcanvas@31f7eab)
 stats     * 3.6.1      2019-07-05 local                             
 tools       3.6.1      2019-07-05 local                             
 utils     * 3.6.1      2019-07-05 local                             
 withr       2.1.2      2018-03-15 CRAN (R 3.5.1)

get_course_gradebook(course_id) shows maximum 10 entries per assignment_id

I'm really impressed by this package. It's super useful. I've discovered a problem however, and I'm not certain if it is on my end or not. When I tally the number of distinct user_ids associated with a each assignment id the maximum value it gives is 10. For example:

require(dplyr)
df%>%group_by(assignment_id)%>%summarise(n_distinct(user_id))

These are large sections, and while I can confirm that some of the students fail to submit work, the majority of the assignments have been submitted and therefore should have recorded scores. The only thing I can think of that might be causing this is that the default setting on my school's canvas website is to only show 10 entries at a time. This seems like it would be unlikely to really cause an issue, but I'm fresh out of ideas and nobody in my office really knows R well enough to figure this out. Any way you might be able to help would be awesome. I'll mail you a giant bag of candy if you can help me figure this out.

rcanvas:::process_response returns list not data.frame

Hi,

thanks for this amazing work! I just started using rcanvas (v0.0.0.9001), but some get_x functions not work. For example, get_course_items fails with:

Error in UseMethod("mutate") : no applicable method for 'mutate' applied to an object of class "list"

I digged a little into it and to me it seems that the internal function rcanvas:::process_response causes the problem, as it returns a list of (one) data frame. For get_course_items it works, when I change the last line in the function code to be:

rcanvas:::process_response(url, args)[[1]] %>% dplyr::mutate(course_id = course_id)

But, probably, process_response needs a fix.

CU, Martin.

New Maintainer of rcanvas?

rcanvas is no longer relevant to my work, and I no longer have a strong, vested interest in maintaining it. If anyone is, please reach out!

Error in `get_submissions?

When I try to use the get_submissions for assignments with a type_id I am getting the following:
Error in canvas_query(url, args, "GET") : Not Found (HTTP 404).

Are anyone else experiencing this issue? I am using the for by @rmtrane as that version seems to be most up to date.

get_course_items() and get_course_gradebook() error in UseMethod("mutate:_")

I get the the following error message when running get_course_items() and get_course_gradebook(), using a script that previously worked (I guess because of a dplyr update):

Error in UseMethod("mutate_") :
no applicable method for 'mutate_' applied to an object of class "list"
In addition: Warning message:
mutate_() is deprecated as of dplyr 0.7.0.
Please use mutate() instead.
See vignette('programming') for more help

get sections from course

Hi,

Users may want to split up outcomes for sections (instead of groups). Perhaps something like the following could be added? (which seem to work.) These are just get functions, but I can imagine that people also may want to use create functions...

get_sections <- function(course_id){
url <- paste0(rcanvas:::canvas_url(), paste("courses", course_id, "sections",
sep = "/"))
args <- list(per_page = 100)
include <- rcanvas:::iter_args_list(NULL, "include[]")
args <- c(args, include)
rcanvas:::process_response(url, args)
}

get_section_users <- function (section_id){
url <- paste0(rcanvas:::canvas_url(), paste( "sections", section_id, "enrollments",
sep = "/"))
args <- list(per_page = 100)
include <- rcanvas:::iter_args_list(NULL, "include[]")
args <- c(args, include)
rcanvas:::process_response(url, args)
}

get_submissions() error

When I try to use the get_submissions for assignments with a type_id I am getting the following:
Error in canvas_query(url, args, "GET") : Not Found (HTTP 404).

Are anyone else experiencing this issue? I am using the for by @rmtrane as that version seems to be most up to date.

Contact students via Message?

Hello, I've successfully installed and started using this great package. What I'd like to do is contact students based on their id's via Canvas' message system. Eg, contact all the students who didn't submit a quiz, etc.

I've looked through the help extensively and I can't seem to find such a function. Am I missing it?

keyring does not exist - issue

Hello everyone,

So, I decided to make a dashboard for myself to test rcanvas. However, while reading through the documentation and in particular keyring's package documentation, I have been having some issues trying to test publish my flexdashboard on shiny or rsconnect and it seems to be stuck on a error that reads as follows in my logs:

Warning: Error in b__file_keyring_autocreate: The 'system' keyring does not exists, create it first!

I was wondering if anyone had some insight on that? I am most likely not setting my keyring correctly and I searched around and have been having a difficult time with. Any suggestions? Any tips would help dearly. I also use the following to try to self help but no luck.

r-lib/keyring#68
https://www.youtube.com/watch?v=M6fz7RXEkLk

Thanks in advance!

Directly call a page

Great idea, great package. I need to study in more detail how the students performed on different quiz questions. The get_submissions just gives the total score, not the breakdown by question. With get_course_items I see this quiz_statistics_url and the quiz_statistics_report. Is there a way to access these URLs directly? Maybe I'm missing something.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.