automation using scripting and the canvas api
DESCRIPTION
A talk from the Washington Canvas User Group 2014 meeting, about using PHP to automate tasks using the Canvas LMS API. Sample code is available at https://github.com/drlippman/canvas-scriptsTRANSCRIPT
Automation using Scripting and the Canvas API
David LippmanPierce College
Lumen Learning
Outline
• Quick overview of the Canvas API
• Why would we want to use it?
• Examples of scripting against the API
• Examples of scripting against export files
API
API = Application Programming Interface
A way for other programs to access data or make changes in Canvas courses
https://canvas.instructure.com/doc/api/
API
“REST”: Basic GET/PUT/POST HTTP calls
JSON format returnhttps://domain.instructure.com/api/v1/courses
Authentication
HTTP Authorization Header
Send access token in the query string
https://domain.instructure.com/api/v1/courses?access_token=<ACCESS-TOKEN>
Generating a Token
Generating a TokenScroll down…
Generating a Token
Generating a Token
So where does that get us?
or
Why should we care?
Use Case 1: Adding Attribution
Course with 100+ text pagesAll needed a Creative Commons attribution
statement added
Option 1: Edit each by handOption 2: Modify an export fileOption 3: Use the API!
The General Idea
Call the page list.
https://domain.instructure.com/api/v1/courses/12345/pages
The General Idea
Call the page list. Repeat if needed.
$endpoint = “/api/v1/courses/$courseid/pages/”;$itemlist = json_decode( file_get_contents( ‘https://’.$domain.$endpoint. ‘?per_page=50&page=‘.$pagecnt. ‘&access_token=‘.$token ));
foreach ($itemlist as $item) { $url = $item->url;
The General Idea
Grab the wiki page body.
The General Idea
Grab the wiki page body. Add attribution.
$endpoint = “/api/v1/courses/$courseid/pages/$url”;$page = json_decode( file_get_contents( ‘https://’.$domain.$endpoint. ‘?access_token='.$token ));$html = $page->body;$html .= $attribution;
The General Idea
Send back
The General Idea
Send back using CURL
$endpoint = “/api/v1/courses/$courseid/pages/$url”;$ch = curl_init(‘https://’.$domain.$endpoint. ‘?access_token=’.$token );curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");curl_setopt($ch, CURLOPT_POSTFIELDS, ‘wiki_page[body]=’.urlencode($html));$response = curl_exec($ch);
Time to Library-ize
require("canvaslib.php");
$api = new CanvasLMS($token,$domain);
$pages = $api->getPageList($courseid);
foreach ($pages as $id=>$name) {
$body = $api->getPageData($courseid, $id, 'body');
$body .= $attribution;
$api->updatePage($courseid, $id,
array("body"=>$body));
}
Use Case 2: Assignment Settings
Adding Instructions to all Assignments in a course
Use Case 2: Assignment Settings
$assn = $api->getAssignmentList($courseid);
foreach ($assn as $id=>$name) {
$api->updateAssignment($courseid, $id,
array(“description”=>$text));
}
Use Case 3: Fixing links
foreach ($pages as $id=>$name) {
$body = $api->getPageData($courseid, $id, 'body');
$body = str_replace(“oldsite.com”,“newsite.com”,
$body);
$api->updatePage($courseid, $id,
array("body"=>$body));
}
Use Case 4: Removing Links
foreach ($pages as $id=>$name) {
$body = $api->getPageData($courseid, $id, 'body');
$body = preg_replace(
'/<a[^>]*badsite[^>]*>(.*?)<\/a>/sm',
' $1 ', $body);
$api->updatePage($courseid, $id,
array("body"=>$body));
}
Use Case 5: Rehosting Images
preg_match_all(
‘/images\.badsite\.com[^>]*(gif|png|jpg)/‘,
$str, $matches);
foreach ($matches[0] as $m) {
$bn = basename($m);
cp(‘http://’.$m, ’./imgs/’.$bn);
$str = str_replace($m, ‘newhost.com/’.$bn, $str);
}
General purpose, web-based tool
AppendReplaceSearch-and-replaceRegex search-and-replace
http://www.imathas.com/canvas/canvassearch.html
Alternate Approach
Working with Exports
Upsides:• Can be faster for large numbers of pages• Can look at changes before uploading
Downsides• Can’t be done on a live class• Have to make sense of the file format
Working with Exports
• Canvas exports are based on Common Cartridge
• Exports are renamed zip files• Exports contain XML, HTML, and files• Main file is imsmanifest.xml– <resource> shows type and location of items– <item> shows item structure (modules)
require("phpQuery-onefile.php");
$zip = new ZipArchive;$zip->open($file);
phpQuery::newDocumentXML( $zip->getFromName("imsmanifest.xml"));
$ref = pq("resource");foreach ($ref as $r) {
$reflist[pq($r)->attr("identifier")] = pq($r)->attr("href");
$reftype[pq($r)->attr("identifier")] = pq($r)->attr("type");}
$items = pq(“item”);
foreach ($items as $item) {
$iref = pq($item)->attr("identifierref");
if (isset($reftype[$iref]) &&
$reftype[$iref]=="webcontent") {
$filename = $reflist[$iref]);
$html = $zip->getFromName($filename);
$html = str_replace(‘</body>’,
$attribution.’</body>’, $html);
$zip->addFromString($filename, $html);
}
}
Sample Code
https://github.com/drlippman/canvas-scripts
• A simple library for doing API calls• A sample program using the library• The web-based general purpose tool• Search-and-replace in a cartridge example