Skip to content

Instantly share code, notes, and snippets.

@brianjmiller
Last active November 7, 2023 17:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save brianjmiller/ef15ce14dd726ae2f558 to your computer and use it in GitHub Desktop.
Save brianjmiller/ef15ce14dd726ae2f558 to your computer and use it in GitHub Desktop.
Tin Can Statement Pipe Utility
  • Install TinCanJS dependency using npm install tincanjs
  • Configure to and from LRSs
  • Adjust statement "linting" (or empty completely)
  • Execute with node toFrom.js
var TinCan = require("tincanjs"),
source,
stream;
//TinCan.enableDebug();
source = new TinCan.LRS (
{
endpoint: "https://cloud.scorm.com/tc/public/",
username: "test",
password: "pass"
}
);
Stream = function () {
console.log("Stream.constructor");
};
Stream.prototype = {
fetchStatements: function (moreUrl) {
console.log("Stream.fetchStatements");
var self = this;
if (moreUrl !== null) {
source.moreStatements(
{
url: moreUrl,
callback: this.processStatementsResult.bind(this)
}
);
return;
}
source.queryStatements(
{
params: {
/*activity: {
id: ""
},
related_activities: true*/
},
callback: this.processStatementsResult.bind(this)
}
);
},
processStatementsResult: function (err, sr) {
console.log("Stream.processStatementsResult");
var i,
batch;
if (err !== null) {
console.log("Stream.processStatementsResult query/more failed: ", err, sr);
return;
}
if (sr.statements.length > 0) {
console.log("Stream.processStatementsResult - printing batch of statements: ", sr.statements.length);
this.printStatements(sr.statements);
}
console.log("Stream.processStatementsResult - more link: ", sr.more);
if (sr.more !== null) {
this.fetchStatements(sr.more);
}
},
printStatements: function (sts) {
console.log("Stream.printStatements");
var i;
for (i = 0; i < sts.length; i += 1) {
console.log(i, sts[i].id, sts[i].timestamp, sts[i].actor.mbox, sts[i].verb.id, sts[i].target.id);
}
}
};
stream = new Stream ();
stream.fetchStatements(null);
var TinCan = require("tincanjs"),
StatementPipe,
to,
from,
pipe,
BROWSER_EXT = "http://id.tincanapi.com/extension/browser-info",
totalSent = 0,
batch = 0;
//TinCan.enableDebug();
to = new TinCan.LRS (
{
endpoint: "https://cloud.scorm.com/tc/---/sandbox/",
username: "",
password: "",
allowFail: false
}
);
from = new TinCan.LRS (
{
endpoint: "https://cloud.scorm.com/tc/---/sandbox/",
username: "",
password: "",
version: "0.95",
allowFail: false
}
);
StatementPipe = function () {
//console.log("StatementPipe.constructor");
};
StatementPipe.prototype = {
fetchStatements: function (moreUrl) {
//console.log("StatementPipe.fetchStatements");
if (moreUrl !== null) {
from.moreStatements(
{
url: moreUrl,
callback: this.processStatementsResult.bind(this)
}
);
return;
}
from.queryStatements(
{
params: {
ascending: true
},
callback: this.processStatementsResult.bind(this)
}
);
},
lintStatements: function (sts) {
//console.log("StatementPipe.lintStatements", sts.length);
var i,
result = [];
for (i = 0; i < sts.length; i += 1) {
if (sts[i].context === null) {
console.log("StatementPipe.lintStatements - skipping (no context): ", sts[i].id);
continue;
}
if (sts[i].context.extensions === null) {
console.log("StatementPipe.lintStatements - skipping (no extensions): ", sts[i].id);
continue;
}
if (typeof sts[i].context.extensions.browser !== "undefined") {
sts[i].context.extensions[BROWSER_EXT] = sts[i].context.extensions.browser;
delete sts[i].context.extensions.browser;
}
result.push(sts[i]);
sts[i].authority = null;
}
return result;
},
processStatementsResult: function (err, sr) {
//console.log("StatementPipe.processStatementsResult");
var sts,
myBatch;
batch += 1;
myBatch = batch;
if (err !== null) {
console.log(myBatch + ": StatementPipe.processStatementsResult query/more failed: ", err, sr);
return;
}
if (sr.statements.length > 0) {
sts = this.lintStatements(sr.statements);
console.log(myBatch + ": StatementPipe.processStatementsResult - sending statements: ", sts.length);
if (sts.length > 0) {
totalSent += sts.length;
to.saveStatements(
sts,
{
callback: function (err, result) {
this.processSaveStatements(err, result, myBatch);
}.bind(this)
}
);
}
}
if (sr.more !== null) {
this.fetchStatements(sr.more);
}
},
processSaveStatements: function (err, result, batch) {
//console.log(batch + ": StatementPipe.processSaveStatements");
if (err !== null) {
console.log(batch + ": StatementPipe.processSaveStatements - failed to store statements: ", err, result.responseText);
console.log(batch + ": StatementPipe.processSaveStatements - failed to store statements, aborting ");
process.exit(1);
}
console.log(batch + ": StatementPipe.processSaveStatements statements saved");
}
};
pipe = new StatementPipe ();
pipe.fetchStatements(null);
@arvind02
Copy link

arvind02 commented Sep 2, 2020

Hello Brian
This gist is awesome and helped me a lot :)
Very small thing I just wanted to point out here. In list.js line no 64, the value of sr.more is not always null. Its sometimes "" or blank.
So might wants to update the condition.

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment