Created
September 28, 2021 17:35
-
-
Save FrenjaminBanklin/cc6612672e24a850d720a6d40ef5381e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
End result should look like: | |
{ | |
"@context": "http://purl.imsglobal.org/ctx/caliper/v1p1", | |
"actor": "https://localhost/api/user/3", | |
"action": "LoggedIn", | |
"object": "https://localhost/api/system", | |
"target": "https://localhost/api/draft-content/e2da1959-ed6e-4365-bb79-7104d1e13123", | |
"eventTime": "2021-09-08T20:16:53.569Z", | |
"edApp": "https://localhost/api/system", | |
"id": "urn:uuid:e6c506e3-259e-43bd-908f-c3ff58679ab7", | |
"session": "https://localhost/api/session/H72bxJobCnHwYLZX-k6T4E8vCtpuTFZ1", | |
"extensions": { | |
"internalEventId": "46" | |
}, | |
"type": "SessionEvent" | |
} | |
*/ | |
const db = require('../server/db') | |
const createCaliperEvent = require('../server/routes/api/events/create_caliper_event') | |
// unclear if this is configured somewhere already or if we'll just have to make assumptions | |
const hostname = 'https://localhost' | |
const args = process.argv.slice(2) | |
const eventId = args[0] | |
// most of the Caliper event object is based on a request, which we won't have | |
// we'll have to build a fake one over a few steps | |
const fakeRequestObject = { | |
body: {} | |
} | |
console.log('attempting to convert Obojobo event to Caliper event') | |
db.one( | |
`SELECT * | |
FROM events | |
WHERE id = $[eventId]`, | |
{ eventId } | |
).then(eventObject => { | |
if ( ! eventObject ) { | |
console.log('no event found with given id') | |
return | |
} | |
fakeRequestObject.body.event = eventObject | |
const userPromise = db.one( | |
`SELECT * | |
FROM users | |
WHERE id = $[eventUserId]`, | |
{ | |
eventUserId: eventObject.actor | |
} | |
) | |
const sessionPromise = db.one( | |
`SELECT * | |
FROM sessions | |
WHERE expire >= $[eventTimestamp] | |
AND sess->>'currentUserId' = $[eventUserId] | |
ORDER BY expire ASC | |
LIMIT 1`, | |
{ | |
eventTimestamp: eventObject.created_at, | |
eventUserId: eventObject.actor | |
} | |
) | |
const visitPromise = db.one( | |
`SELECT * | |
FROM visits | |
WHERE id = $[eventVisitId]`, | |
{ | |
eventVisitId: eventObject.visit_id | |
} | |
).then(visitObject => { | |
if (visitObject) { | |
if (visitObject.launch_id) { | |
return db.oneOrNone( | |
`SELECT * | |
FROM launches | |
WHERE id = $[visitLaunchId]`, | |
{ | |
visitLaunchId: visitObject.launch_id | |
} | |
).then(launchObject => { | |
visitObject.launch = launchObject | |
return visitObject | |
}) | |
} else { | |
return visitObject | |
} | |
} | |
}) | |
Promise.all([userPromise, sessionPromise, visitPromise]).then(([userObject, sessionObject, visitObject]) => { | |
if ( ! userObject ) { | |
console.log('no user found for event') | |
return | |
} | |
if ( ! sessionObject ) { | |
console.log('no session found for event') | |
return | |
} | |
if ( ! visitObject ) { | |
console.log('no visit found for event') | |
return | |
} | |
fakeRequestObject.currentUser = userObject | |
fakeRequestObject.currentDocument = { | |
draftId: eventObject.draft_id, | |
contentId: eventObject.draft_content_id | |
} | |
sessionObject.id = sessionObject.sid | |
sessionObject.oboLti = { | |
launchId: visitObject.launch.id, | |
body: visitObject.launch.data | |
} | |
fakeRequestObject.session = sessionObject | |
// Note that this will not work for every type of event | |
// Maybe have a check after this; if caliperEventObject is null/undefined, do something else | |
caliperEventObject = createCaliperEvent(fakeRequestObject, hostname) | |
if(caliperEventObject) { | |
// override a few things based on the original event | |
caliperEventObject.eventTime = eventObject.created_at | |
caliperEventObject.extensions.internalEventId = eventObject.id | |
} else { | |
// the given event probably isn't supported by the 'create from event + request' model | |
// the correct handler function will need to be chosen based on the event's action type | |
// see the list below, compare to the code that's actually creating the real caliper events | |
// to figure out which function is necessary to match the event's action type | |
} | |
console.log('GENERATED CALIPER EVENT OBJECT') | |
console.log(caliperEventObject) | |
}) | |
}) | |
/* | |
all action types | |
assessment:attemptEnd | |
assessment:attemptInvalidated | |
assessment:attemptResume | |
assessment:attemptScored | |
assessment:attemptStart | |
assessment:recordResponse | |
assessment:setResponse | |
draft:copy | |
lti:launch | |
lti:pickerLaunch | |
lti:replaceResult | |
materia:ltiLaunchWidget | |
materia:ltiPickerLaunch | |
materia:ltiScorePassback | |
media:hide | |
media:resetZoom | |
media:setZoom | |
media:show | |
nav:close | |
nav:goto | |
nav:gotoPath | |
nav:lock | |
nav:next | |
nav:open | |
nav:prev | |
nav:toggle | |
nav:unlock | |
question:checkAnswer | |
question:hide | |
question:hideExplanation | |
question:recordResponse | |
question:retry | |
question:revealAnswer | |
question:scoreClear | |
question:scoreSet | |
question:setResponse | |
question:showExplanation | |
question:submitResponse | |
question:view | |
score:clear | |
score:set | |
viewer:close | |
viewer:inactive | |
viewer:initialView | |
viewer:leave | |
viewer:open | |
viewer:return | |
viewer:returnFromInactive | |
visit:create | |
visit:start | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment