Spit and Tape to Get Some Data

We're using Canvas LMS in our district. There are some things I appreciate and things I appreciate...less. One of which is when a main feature doesn't work.

Luckily, the Canvas API gives me some leeway in fixing things that Instructure doesn't seem know is broken.

I'm supporting teachers using Outcomes in their courses. Assignments can be tagged with relevant standards and recorded in a nice color-coded chart over time. I came across a big problem where students couldn't see their aggregated scores. There's no point in giving rubric feedback if students can't see those scores.

I thought it might be a fluke, so I tried reaching the student results through the API. It works as a teacher, but not as a student. There's a pipe broken somewhere on the Internet.

[File large bug report, crack knuckles.]

The approach

The easy fix would have been to hit the Canvas API to get this fixed, but student accounts came back with no data. So, I needed an intermediate, server-side account to do the work.

Earlier this semester, I set up an internal web app to manage reconciling grades. This was built in Flask so it was easy to add an endpoint as an API. I've been really digging the canvasapi Python package from UCF because it's so versatile and makes working with objects so easily.

So, I ended with:

  • JS client listents for the user to click on a tab in the gradebook.
  • Hit the Flask endpoint to start the server call.
  • Return the requested objects.
  • Process the objects in the client and append to the page.

The code

Here's the commented code for a simple implementation using Flask and some Javascript.

Change Course Role in Canvas via the API

Continuing my Canvas excursions...

We recently made a change where teachers could not manually add students to their courses. The change was made because manually enrolling a student breaks the grade passback to our SIS, which causes double the work to fix the problem in the first place.

But, this also affects manually-created courses that don't need the grade passback. One workaround is to add all students as a TA or teacher, but then you run into issues where students have access to grades.

The API doesn't allow you to directly change a user's enrollment status. You need to delete the user object from the course and then re-enroll to change the status. The change in the UI on the website does the same thing, but they make it look nice with a dropdown and it doesn't actually tell you that the user was deleted and re-added all in one step.

The nice thing about the API method is that you can set their enrollment state to active by default, which removes the course invitation notification and acceptance step for someone who is just having their status changed.

The example below is what I used to convert all students who were added as TAs back into Students. As always, I'm using the UCF Open Python library to handle the API calls.

from canvasapi import Canvas

canvas = Canvas('your_url', 'your_key')

course = canvas.get_course(course_id)

enrollments = course.get_enrollments(type='TaEnrollment')

for stu in enrollments:
    user_id = stu.user_id

    # the `deactivate` method takes a **kwarg to define what type of deactivation.
    # accepted strings: ['conclude', 'delete', 'deactivate', 'inactivate']
    stu.deactivate(task='delete')
    course.enroll_user(user_id, 'StudentEnrollment', enrollment_state='active')

This does wipe out the 'Last Activity' field in the People tab, so if that's important to you, make the change before the course is published. I made the change for a user, going from student to teacher and back with no loss of grade data, which was nice to see.