Callisto

A simple, queryable Caliper event store.

Build Status Code Climate

Callisto Vision

Most Learning Record Stores (LRSes) that support IMS Global Caliper (or XAPI) today just store the JSONB of the event payload in some fashion. There is no built-in query capability. You must write rather elaborate JSON queries to gain insight into student usage patterns based on the events.

Callisto provides the same generic event store. But it decomposes the various event types into their own structured forms and then exposes specific REST queries for each event type. It is our hope that the Callisto query web services eventually become extensions to the IMS Global Caliper standard.

Code and Architecture

Callisto is a very simple Ruby on Rails app with models and controllers for (eventually) all important Caliper events likely to be used for query. It is written for Postgres due to PG's excellent JSONB and fulltext support which are likely to be helpful. It could be ported to other relational databases. Given its focus on web service query, Callisto will stick very closely to the generated Rails scaffolding for the models for each Caliper event.

Code is available on GitHub

All Callisto code is open source via Apache License 2.0.

Endpoints

Getting your token

You will need to sign in to get your access-token, uid, and client. These attributes will be used in all subsequent requests to authenticate your user.

Request

curl -XPOST -i -H 'Accept: application/json' -H 'Content-Type: application/json' https://www.opencallisto.org/auth/sign_in -d '{"email": "mail@example.com", "password": "password" }'

Response Headers

access-token: lW1c60hYkRwAinzUqgLfsQ token-type: Bearer client: W_xCQuggzNOVeCnNZbjKFw expiry: 1426610121 uid: testemail@mydomain.com

Every other request should have headers set similar to below

curl -XGET -v -H 'Content-Type: application/json' -H 'access-token: lW1c60hYkRwAinzUqgLfsQ' -H 'client: W_xCQuggzNOVeCnNZbjKFw' -H "uid: testemail@mydomain.com" https://www.opencallisto.org/example_endpoint

Populating Caliper Events

To store Caliper events in Callisto use the CaliperEvent model Create method. In the example below the sensor value is just a unique URI (it happens to be a unique URI on opened.com). The data consists of multiple valid Caliper events.

curl -H "Content-Type: application/json" -d '{"caliper_event":{"payload":{"sensor": "https://opened.com/sensors/MediaEvent","data":[{"a":"1"},{"b":"2"}]}}}' https://www.opencallisto.org/caliper_events

Sample Caliper Event

Below is a sample Caliper event (specifically MediaEvent) based on one of the IMS Caliper fixtures. Of particular note is the learningObjectives attribute as that was not fleshed out in the fixture example. It also uses IMS CASE item URLs for the learningObjective's ID and in an extension attribute called "case_item". Other parts of the MediaEvent that aren't required are left out for simplicity.

```json {

"@context": "http://purl.imsglobal.org/ctx/caliper/v1/Context", "@type": "MediaEvent", "actor": { "@id": "https://example.edu/user/554433", "@type": "Person", "dateCreated": "2015-08-01T06:00:00.000Z" }, "action": "Ended", "object": { "@id": "https://example.com/super-media-tool/video/1225", "VideoObject", "name": "American Revolution - Key Figures Video", "learningObjectives": [ { "@id": "http://opensalt.opened.com/cftree/item/19033", "@type": "LearningObjective", "extensions": {“caseItemURI”: “http://opensalt.opened.com/cftree/item/19033”}, "dateCreated": "2015-08-01T06:00:00.000Z" } ] } } ```

Querying for Event Types

Once Caliper events are stored with the "caliper_events/create" method they can be retrieved using various index methods for each event type.

AssessmentItemEvents

Various queries on AssessmentItemEvents can be performed with the assessmentitemevents.json endpoint.

Parameters include: * actorid - the ID of the assessment item taker, e.g. "https://example.edu/user/554433" * actionid - what happened with the assessment item, e.g. "http://purl.imsglobal.org/vocab/caliper/v1/action#Completed" * objectid - the assessment item ID itself, e.g. "https://example.edu/politicalScience/2015/american-revolution-101/assessment/001" * generatedid - the ID of the assessment attempt, e.g. ""https://example.edu/politicalScience/2015/american-revolution-101/assessment/001/item/001/response/001"" * learningobjective - all GradeEvents for a particular learning objective, expressed as a CASE URL * ispartof - the id of the assessment, e.g. "https://www.opened.com/resources/1184041" * eventtime - the date the assessment item was recorded, e.g. "2017-04-12"

Example REST call (all assessment item events for specified user): sh curl https://opencallisto.org/assessment_item_events.json?actor_id=https://example.edu/user/554433

GradeEvents

Various queries on GradeEvents can be performed with the grade_events.json endpoint.

Parameters include: * actorid - the ID of the assessment taker, e.g. "https://example.edu/user/554433" * objectid - the ID of the assessment attempt, e.g. "https://example.edu/politicalScience/2015/american-revolution-101/assessment/001/attempt/5678" * objectassignable - the ID of the assessment, e.g. "https://example.edu/politicalScience/2015/american-revolution-101/assessment/0011" * generatedid - the ID of the assessment result, e.g. "https://example.edu/politicalScience/2015/american-revolution-101/assessment/001/attempt/5678/result * learning_objective - all GradeEvents for a particular learning objective, expressed as a CASE URL

Example REST call (all grade events for specified user) : curl https://opencallisto.org/grade_events.json?actor_id=https://example.edu/user/554433

AssessmentEvents

Various queries on AssessmentEvents can be performed with the grade_events.json endpoint.

Parameters include: * actorid - the ID of the assessment taker, e.g. "https://example.edu/user/554433" * action - what happened with the assessment, e.g."http://purl.imsglobal.org/vocab/caliper/v1/action#Paused" * objectid - the ID of the assessment, e.g. "https://A0501617.opened.com/assessmentbank/0235872d-636a-4467-94d0-5ab6842463ed/assessment/1094264" * generatedid - the ID of the assessment attempt, e.g. "https://example.edu/politicalScience/2015/american-revolution-101/assessment/001/attempt/5678/result * learningobjective - all GradeEvents for a particular learning objective, expressed as a CASE URL * eventtime - the date the assessment was recorded, e.g. "2017-04-12" Example REST call (all grade events for specified user) : curl -H 'Content-Type: application/json' -H 'access-token: lW1c60hYkRwAinzUqgLfsQ' -H 'client: W_xCQuggzNOVeCnNZbjKFw' -H "uid: testemail@mydomain.com" https://opencallisto.org/assessment_events.json?actor_id=https://example.edu/user/554433

MediaEvents

Various queries on MediaEvents can be performed with the media_events.json endpoint.

Parameters include: * actorid - the ID of the media viewer, e.g. "https://example.edu/user/554433" * actionid - what happened with the video, e.g. "http://purl.imsglobal.org/vocab/caliper/v1/action#Ended" * objectid - the URL of the video itself, e.g. "https://example.com/super-media-tool/video/1225" * learningobjective - the learning objective of the video, expressed as the CASE URL for the standard, e.g. http://opensalt.opened.com/cftree/item/19033

Example REST call (all grade events for specified user) : curl -H 'Content-Type: application/json' -H 'access-token: lW1c60hYkRwAinzUqgLfsQ' -H 'client: W_xCQuggzNOVeCnNZbjKFw' -H "uid: testemail@mydomain.com" https://opencallisto.org/media_events.json?actor_id=https://example.edu/user/554433

Database Schema Generation Rules

Callisto relies on Postgres to store the attributes of each Caliper event individually. This includes columns such as actorid, actionid, and object_id. As new Caliper events get created the following rules should be followed for generating Postgres tables and their columns. The rules here are also useful for code the expects to populate rows to the table.

Table names (following the ActiveRecord convention) should be the Caliper event name (its type) with underscores between words. For example the Caliper AssessmentEvent has the table name "assessment_events".

The columns that must always be present include: * id - a unique ID for the row stored in the table. This is necessary for the ActiveRecord ORM to function.
ables for each event should be available with the following rules. Code that populates the table does not have to populate this column * eventid - the Caliper id attribute should be represented as eventid in the table to not collide with the id column mentioned above * payload - a direct duplicate of the JSON of the original Caliper payload * client - this column will be the identity of the logged in application sending Caliper events or querying for them. It is used to segment the data by particular groups.

The Caliper event type attribute should NOT be present in the Postgres table, as it is implied by the table name.

All other Caliper event attributes SHOULD be present in the table and abide by the following rules: * The column names should be the exact Caliper attribute name but converted to underscores when there is more than one word instead of camelCase. For example the "eventTime" attribute becomes "eventtime".
* Non-valid identified characters (alphanumeric plus underscore) should be stripped. So the Caliper event attribute "@context" becomes "context". * For attributes that are embedded inside other attributes, an underscore should be placed in between the parent and child attribute to create a column name. For example the id attribute inside the actor attribute would be placed in the column "actor
id".

Credits

Callisto is a project from ACT, Inc..

Current contributors include Adam Blum, Lucas Campbell and Lars Burgess.

It is open source and available via Apache License 2.0. Please submit pull requests to us via the GitHub repo if you make enhancements. Email us if you want to discuss your contributions.

IMS Caliper is a trademark of IMS Global