1
0
Files
coldcall_lti/README.md
Benjamin Mako Hill 52afc57ebd Phase 2: LTI plumbing, roster sync, and fake-launch dev mode
OIDC login, launch, and JWKS endpoints built on pylti1p3next's Flask
adapter, with launch-claim processing split into a testable module.
Instructor launches refresh the roster through NRPS; the sync code is
source-agnostic and also drives the dev-mode fake roster. Dev mode
(COLDCALL_DEV_MODE=1) provides fake instructor and student personas
that set up the same session state as a real launch, so the rest of
the app can be developed before a Canvas Developer Key exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 16:33:08 -07:00

104 lines
4.1 KiB
Markdown

# coldcall-lti
A Canvas external tool (LTI 1.3) 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.
## 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
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, which means
adds and drops are picked up automatically rather than reconciled by
hand.
Selection uses the same weighting as the manual system it replaces: each
answered call divides a student's weight by the course's weight factor
(default 2), so students who have answered more questions become
progressively less likely to be called. Each course can instead use
"cycle" mode, which shuffles the roster and calls everyone exactly once.
These, along with whether students can see their own assessments, are
per-course settings.
## Layout
- `coldcall_lti/models.py` — SQLAlchemy models: courses (with their
settings), students, enrollments, opt-outs, and calls, plus the query
helpers that feed selection.
- `coldcall_lti/selection.py` — the weighted and cycle selection logic.
Kept free of database and web dependencies so it can be tested and
reasoned about on its own.
- `coldcall_lti/__init__.py` — the Flask application factory.
- `migrations/` — alembic migrations. The schema avoids
database-specific types so the same migrations run on SQLite (the
default) and MariaDB/MySQL; switching is a matter of changing
`COLDCALL_DATABASE_URL`.
- `tests/` — pytest suite covering selection behavior and the model
helpers.
## Setup
Development uses a virtualenv that shares the system's Debian-packaged
libraries (Flask, SQLAlchemy, alembic, pytest) and adds the one
PyPI-only dependency, the maintained `pylti1p3next` fork of PyLTI1p3:
```
python3 -m venv --system-site-packages .venv
.venv/bin/pip install pylti1p3next
.venv/bin/pip install -e .
```
Create the database and run the tests:
```
.venv/bin/python -m alembic upgrade head
.venv/bin/python -m pytest tests/
```
Configuration is by environment variable: `COLDCALL_DATABASE_URL` (any
SQLAlchemy URL; defaults to an SQLite file under `instance/`),
`COLDCALL_SECRET_KEY` for Flask sessions, `COLDCALL_LTI_CONFIG` (path
to the LTI platform configuration), and `COLDCALL_DEV_MODE=1` to enable
the fake-launch pages.
## Connecting to Canvas
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:
```
openssl genrsa -out instance/private.key 4096
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
changes appear without any manual step.
## Developing without Canvas
Because a Developer Key takes institutional approval to get, the app
has a fake-launch mode for local development:
```
COLDCALL_DEV_MODE=1 .venv/bin/flask --app coldcall_lti run --debug
```
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
embedding requires in production (SameSite=None; Secure), which would
otherwise break plain-http localhost use.