Speak of the LMS generically, not Canvas specifically
The tool targets any LTI 1.3 platform; Canvas is the primary target but nothing outside the Canvas-specific custom variable substitutions depends on it. User-facing strings and the README now say "LMS" except where a mechanism genuinely is Canvas's (the $Canvas.* / com.instructure.* substitutions and their handling), and the README states plainly that the tool has so far been exercised only against the saltire emulator, not yet a production LMS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
56
README.md
56
README.md
@@ -1,19 +1,23 @@
|
||||
# coldcall-lti
|
||||
|
||||
A Canvas external tool (LTI 1.3) for managing cold calls in case-based
|
||||
An LTI 1.3 external tool for managing cold calls in case-based
|
||||
classes: it selects students to call using weighted randomness, records
|
||||
what happened with each call, lets students report planned absences, and
|
||||
reports participation data back to both instructor and students. It
|
||||
replaces a manual workflow built on exported rosters, Google Forms, and
|
||||
local scripts.
|
||||
local scripts. It should work with any LMS that implements LTI 1.3
|
||||
(LTI Advantage); Canvas is the primary target and the platform the
|
||||
Canvas-specific conveniences below are written for. So far it has been
|
||||
exercised only against the saltire LTI emulator (see
|
||||
`docs/SALTIRE.md`) — not yet against any production LMS.
|
||||
|
||||
## How it works
|
||||
|
||||
The tool is a Flask application that Canvas launches over LTI 1.3. A
|
||||
single URL serves everyone: Canvas identifies the person and course on
|
||||
The tool is a Flask application that the LMS launches over LTI 1.3. A
|
||||
single URL serves everyone: the LMS identifies the person and course on
|
||||
each launch, so instructors get the call-list and reporting views
|
||||
while students get the absence form and their own history. The roster
|
||||
comes from Canvas through the Names and Role Provisioning Service,
|
||||
comes from the LMS through the Names and Role Provisioning Service,
|
||||
which means adds and drops are picked up automatically rather than
|
||||
reconciled by hand.
|
||||
|
||||
@@ -105,15 +109,17 @@ SQLAlchemy URL; defaults to an SQLite file under `instance/`),
|
||||
to the LTI platform configuration), and `COLDCALL_DEV_MODE=1` to enable
|
||||
the fake-launch pages.
|
||||
|
||||
## Connecting to Canvas
|
||||
## Connecting to an LMS
|
||||
|
||||
The tool speaks LTI 1.3, which requires a Developer Key created by a
|
||||
Canvas account admin. The key points Canvas at three endpoints here:
|
||||
`/lti/login` (OIDC initiation), `/lti/launch` (the launch target), and
|
||||
`/lti/jwks` (this tool's public keys). The platform side is described
|
||||
in a JSON file — copy `lti_config.example.json` to
|
||||
`instance/lti_config.json` and fill in the client id and deployment id
|
||||
from the Developer Key. Generate the tool's keypair alongside it:
|
||||
Any LTI 1.3 platform can launch the tool; registration means telling
|
||||
the LMS about three endpoints here: `/lti/login` (OIDC initiation),
|
||||
`/lti/launch` (the launch target), and `/lti/jwks` (this tool's public
|
||||
keys). In Canvas this takes a Developer Key created by an account
|
||||
admin; other platforms have their own registration screens for the
|
||||
same information. The platform side is described in a JSON file — copy
|
||||
`lti_config.example.json` to `instance/lti_config.json` and fill in
|
||||
the client id and deployment id from the registration. Generate the
|
||||
tool's keypair alongside it:
|
||||
|
||||
```
|
||||
openssl genrsa -out instance/private.key 4096
|
||||
@@ -121,7 +127,7 @@ openssl rsa -in instance/private.key -pubout -out instance/public.key
|
||||
```
|
||||
|
||||
On each instructor launch the tool refreshes the course roster from
|
||||
Canvas through the Names and Role Provisioning Service, so enrollment
|
||||
the LMS through the Names and Role Provisioning Service, so enrollment
|
||||
changes appear without any manual step. There is also a "Sync roster
|
||||
now" button on the instructor page, and a management command suitable
|
||||
for an hourly cron job on the server, which keeps rosters current even
|
||||
@@ -132,11 +138,13 @@ churn at the start of a term):
|
||||
17 * * * * cd /path/to/coldcall_lti && .venv/bin/flask --app coldcall_lti sync-rosters
|
||||
```
|
||||
|
||||
Courses whose Canvas end date has passed are skipped automatically.
|
||||
Courses whose end date has passed are skipped automatically.
|
||||
|
||||
Student names come from Canvas display names, which already reflect
|
||||
preferred names. Four custom parameters on the Developer Key give the
|
||||
tool everything else it can use from Canvas:
|
||||
Student names come from the LMS's display names, which already reflect
|
||||
preferred names. Canvas users can get more through four custom
|
||||
parameters on the Developer Key (these are Canvas-specific variable
|
||||
substitutions; other platforms may offer equivalents under different
|
||||
names, and the tool works fine without them):
|
||||
|
||||
```
|
||||
pronouns=$com.instructure.Person.pronouns
|
||||
@@ -151,8 +159,8 @@ Canvas attach per-member custom fields) and appear on the live call
|
||||
card, printed lists, and each student's own page. The course dates
|
||||
bound the schedule and date pickers, and the grading scheme becomes
|
||||
importable into the grade display scale with one click in settings.
|
||||
All four degrade gracefully: a course or account without them simply
|
||||
does without.
|
||||
All four degrade gracefully: a course, account, or platform without
|
||||
them simply does without.
|
||||
|
||||
## Opt-outs
|
||||
|
||||
@@ -186,12 +194,12 @@ never matters, and luck of the draw never moves a grade. Parameters
|
||||
settings; grades are computed on demand, reviewed on the instructor's
|
||||
grades page, and shown to students only when the instructor publishes
|
||||
reports. With gradebook passback enabled, a review-then-push page
|
||||
sends the reviewed scores to Canvas via the Assignment and Grade
|
||||
sends the reviewed scores to the LMS gradebook via the Assignment and Grade
|
||||
Services; nothing is ever sent without explicit confirmation.
|
||||
|
||||
Grades are computed in points out of 100 and displayed through a
|
||||
per-course scale: the built-in linear UW 4.0 map, a threshold table
|
||||
(letter grades, importable in one click from the course's own Canvas
|
||||
(letter grades, importable in one click from the course's own LMS
|
||||
grading scheme), or raw points.
|
||||
|
||||
The port was verified against the R engine's rendered reports from a
|
||||
@@ -200,7 +208,7 @@ simulated penalty agrees within Monte Carlo noise. `flask --app
|
||||
coldcall_lti import-legacy <dir>` imports a manual-era class directory
|
||||
for this kind of testing.
|
||||
|
||||
## Developing without Canvas
|
||||
## Developing without an LMS
|
||||
|
||||
Because a Developer Key takes institutional approval to get, the app
|
||||
has a fake-launch mode for local development:
|
||||
@@ -213,7 +221,7 @@ Then open http://localhost:5000/dev and launch as the fake instructor
|
||||
or any of the fake students. This sets up exactly the session state a
|
||||
real launch would, and the fake roster flows through the same sync code
|
||||
as real NRPS data, so everything past the launch behaves identically.
|
||||
Dev mode also relaxes the cookie settings that Canvas's iframe
|
||||
Dev mode also relaxes the cookie settings that LMS iframe
|
||||
embedding requires in production (SameSite=None; Secure), which would
|
||||
otherwise break plain-http localhost use.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user