Canvas Assignment for Zoom Attendance

murphyl
Community Novice
9
6365

Faculty at my institution have been asking for a way to record attendance for Zoom video lectures within a Canvas assignment as attendance makes up a very small percentage of final grades. There is no inbuilt functionality to do this within Canvas so I created a python script that takes a Zoom meeting report, creates a new assignment within Canvas and gives a points score to all attendees. 

 

Caveat: I am not a proficient coder and the script is utilized at the users own risk. We are considering developing it into a production application with GUI or built into Canvas, but have no near term plans to do so - purely a proof of concept at this stage. That being said, I would still appreciate any feedback or information on any modifications you make to it. 

 

Initial Configuration

The script uses the Canvas API to create and grade a new assignment. An access token is required to use the API and this will provide the same level of access as your Canvas account.

  1. In Canvas, click Account then Settings
  2.  Scroll down to Approved Integrations and at the bottom of the integrations list, click + New Access Token
  3. Provide a purpose and expiry date (N.B. Use <2wks to minimize risk. Do not leave the date blank!) and click Generate Token
  4. Copy the access token (When you close this window, you will not be able to view the token again)
  5. Open the python script in your favorite text editor or IDE
  6. Near the end of the script, replace <YOUR API KEY HERE> with your copied access token
  7. A few lines further down, replace <YOUR CANVAS URL> with the URL for your Canvas instance
  8. Save the python script

 

Usage

The Python script does three things: (1) create a new assignment, (2) take the provided Zoom meeting report and extract attendees, (3) add a grade to the assignment for students that attended the Zoom meeting

To use the script

  1. On your Canvas site, go to the Zoom page and click on Previous Meetings
  2. Click Report next to the meeting you want to record attendance for
  3. Click Export as CSV File and save to your computer
  4. Run the Python script. You will be prompted for four things (Variable input does slow down script so you could hard code the course ID and points score) :
    1. Course ID (e.g. 3157 (the four digit number in a URL for any page on the course site))
    2. Name for new assignment (e.g. Attendance 7/27)
    3. The Zoom report file (Browse for the saved CSV file)
    4. Point score for present students (e.g. 1)

If you now navigate to the Assignments section of the Canvas site, you will see a new assignment created with the name provided. In the Grades section (if visible to you) this assignment will be graded for all students that attended the Zoom meeting.

9 Comments
scottdennis
Instructure
Instructure

Thank you for letting us know about the issue with the attached files not being accessible on migrated documents.  The attached files should remained accessible.  We have reached out to the migration engineering team for follow up.

scottdennis
Instructure
Instructure

@A_K_Dekker , would you confirm that you can now download the attached zip file?

Thanks,

SD

A_K_Dekker
Community Participant

Yes, it works now. Thanks @scottdennis!

mikeg
Community Participant

First, thanks for posting this script.  I appreciate it.


Second, some comments:

  1. When setting the API_URL value, be sure to include the leading "https://"
  2. My course ID consisted of the 6 digits after the last / rather than the 4 you indicate (it must vary between institutions).
  3. I had to filter attendance_list to remove the students who later dropped the class using the following code

 

attendance_list = list(filter(lambda x: isinstance(x, str), attendance_list))​

 

  • Changing published to 'False' gave the following error: 
    • /home/user/anaconda3/lib/python3.7/site-packages/canvasapi/requester.py", line 238, in request
       raise Unauthorized(response.json())
      canvasapi.exceptions.Unauthorized: [{'message': 'user not authorized to perform that action'}
    • Any idea why or how to fix this? I confused a few students while trying to debug my changes below.
  • Finally, I've modified the code so that it can
    1. Accept a file name in the command line
    2. Automatically name the assignment using the date

 

 

 

from canvasapi import Canvas
import tkinter as tk
from tkinter import filedialog
import pandas as pd
import sys

# Create new assignment
def create_assignment(assignment_name):
    new_assignment = course.create_assignment({
        "name": assignment_name,
        "submission_types": [
          "none"
        ],
        "points_possible": 1,
        "grading_type": "points",
        "muted": "true", ## originally false
        "published": "true" ## originally true
    })

    print('New assignment created: ', new_assignment)
    return (new_assignment.id)

# Get File
def get_file_path():
    print('Select Attendance Report in File Browser Window')
    root = tk.Tk()
    root.withdraw()

    file_path = filedialog.askopenfilename()
    print('Using', file_path)
    return file_path


# Get attendance list
def get_attendance(data_file):
    attendance_list = data_file['Email'].tolist()
    # print('List of attendees: ', attendance_list)
    # remove any students who have dropped and, thus, whose names are numbers and emails are empty
    attendance_list = list(filter(lambda x: isinstance(x, str), attendance_list))
    # print('Filtered list of attendees: ', attendance_list)
    return attendance_list


def change_attendance(assignment_id, attendance_list, grade):
    # Get students in course
    students_course = course.get_users(enrollment_type=['student'])
    login_ids = {}
    for student in students_course:
        if hasattr(student, 'email') == True:
            login_ids[student.email] = student.id

    # Make all lowercase
    login_ids =  {k.lower(): v for k, v in login_ids.items()}
    attendance_list = map(str.lower,attendance_list)

    # For students in attendance, change grade
    count_student = 0
    for attendee in attendance_list:
        if attendee in login_ids:
            attendee_id = login_ids[attendee]
            assignment = course.get_assignment(assignment_id)
            submission = assignment.get_submission(attendee_id)
            submission.edit(submission={'posted_grade':grade})
            print('Attendee present: ',attendee)
            count_student += 1

    print('Attendance updated. ', count_student, ' students marked present')


### MAIN SCRIPT ###
# INPUTS #
API_Key = 'API_KEY' # Add your Canvas access token here

# Action

# Initiallizing Canvas API
API_URL = "https://INSTITUTION.instructure.com" # Add your Canvas URL here
canvas=Canvas(API_URL,API_Key)

# Access Canvas Course
## courseID = input('Enter Canvas Course ID: ')
courseID = "111111"
course = canvas.get_course(courseID)

use_date_as_name = True

# Load Data
if len(sys.argv) > 1:
    file_path = sys.argv[1]
else:
    file_path = get_file_path()

#attendance_date = pd.read_csv(file_path, usecols= ['Join Time'], nrows = 1, parse_dates=True, infer_datetime_format=True)
attendance_date = pd.read_csv(file_path, nrows = 1).at[0, 'Join Time'][0:5]

print("Date", attendance_date)

data_file = pd.read_csv(file_path, usecols= ['Name','Email'])

    
# Create New Assignment
if use_date_as_name:
    assignment_name = attendance_date
else:
    assignment_name = input('Enter new assignment name: ')

assignment_id = create_assignment(assignment_name)

# Get Zoom Attendance
attendance_list = get_attendance(data_file)

# Grade attendance
## attendance_score = input('Points for attendance: ')
attendance_score = 1
change_attendance(assignment_id, attendance_list, attendance_score)

 

 

 

mikeg
Community Participant

Warning: Above scripts may ignore first student in list!!!

I've discovered that both scripts fail to update the status of the first student listed in the gradebook (or at least that's how it appears to me).  I suspect it's something to do with CANVAS's API ignoring the first entry in a table due to indexing differences, but that's really a guess.  The scripts work AFAIK for the remaining students, but you'll want to double check.  I'm hoping to figure out what's going wrong some time soon.

 

Also, @murphyl , I'd like your okay to use post the code on a public github repo.

 

MatthiasYoung
Community Novice

Hello,

I modified this script to search for attendee name rather than email address, and enable posting to an existing assignment rather than just creating a new assignment. Can you send me the github repo location so I can contribute?

Thanks,
Matthias Young

mikeg
Community Participant

@MatthiasYoung That's great to hear!  Regarding a repo, I didn't create one since I never heard from @murphyl .  I'm in the midst of creating one, however.  I will do so in the next day or two. 

mikeg
Community Participant

Currently the script requires a valid CourseID and API key, which makes debugging and troubleshooting tricky since students get an email each time it's run.  Does anyone know of a test site one could use to troubleshoot?

maguire
Community Champion

You can run it against your test instance and it will not generate e-mails to the student that there is a new grade for the assignment. If your production instance is xxxx.instructure.com then your test instance will usually be xxxx.test.instructure.com