diff --git a/competency-framework/algebra/the-number-system.xml b/competency-framework/algebra/the-number-system.xml index 49c9444..b2f12cf 100644 --- a/competency-framework/algebra/the-number-system.xml +++ b/competency-framework/algebra/the-number-system.xml @@ -3,7 +3,7 @@ URI - http://12.109.40.34/competency-framework/algebra/the-number-system + http://40.129.74.199:8080/competency-framework/algebra/the-number-system The Number System diff --git a/competency-framework/computer-science/basic-programming.xml b/competency-framework/computer-science/basic-programming.xml new file mode 100644 index 0000000..415cda0 --- /dev/null +++ b/competency-framework/computer-science/basic-programming.xml @@ -0,0 +1,94 @@ + + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/basic-programming + + + Basic Programming + + + Basic Programming describes the set of skills needed to create basic computer programs. + + + + + 1.0 + + + Advanced Distributed Learning + + LOMv1.0 + publisher + + + + + + LOMv1.0 + yes + + + Creative Commons Attribution 3.0 Unported license, http://creativecommons.org/licenses/by/3.0/ + + + + 2013-11-19 + + + ADL has created a set of skills needed to successfully begin programming for computers. + + + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-variables + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-functions + + + + URI + http://40.129.74.199:8080/competency-frameworks/computer-science/basic-programming + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-variables + + + + + URI + http://40.129.74.199:8080/competency-frameworks/computer-science/basic-programming + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + + + + URI + http://40.129.74.199:8080/competency-frameworks/computer-science/basic-programming + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-functions + + + diff --git a/competency-framework/computer-science/understanding-flow-control.xml b/competency-framework/computer-science/understanding-flow-control.xml new file mode 100644 index 0000000..f6aa64b --- /dev/null +++ b/competency-framework/computer-science/understanding-flow-control.xml @@ -0,0 +1,124 @@ + + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + + Understanding Flow Control + + + Understanding how to control the process flow within a program. + + + + + 1.0 + + + Advanced Distributed Learning + + LOMv1.0 + publisher + + + + + + LOMv1.0 + yes + + + Creative Commons Attribution 3.0 Unported license, http://creativecommons.org/licenses/by/3.0/ + + + + 2013-11-19 + + + ADL has created a set of skills needed to properly control the processing flow of a program. + + + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-variables + + + URI + http://40.129.74.199:8080/competency/computer-science/if-else + + + URI + http://40.129.74.199:8080/competency/computer-science/case-statements + + + URI + http://40.129.74.199:8080/competency/computer-science/for-loop + + + URI + http://40.129.74.199:8080/competency/computer-science/while-loop + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-variables + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/if-else + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/case-statements + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/for-loop + + + + + URI + http://40.129.74.199:8080/competency-framework/computer-science/understanding-flow-control + + http://www.w3.org/2004/02/skos/core#narrower + + URI + http://40.129.74.199:8080/competency/computer-science/while-loop + + + diff --git a/competency-framework/scorm/choosing-an-lms.xml b/competency-framework/scorm/choosing-an-lms.xml new file mode 100644 index 0000000..ece45dd --- /dev/null +++ b/competency-framework/scorm/choosing-an-lms.xml @@ -0,0 +1,69 @@ + + + + + + URI + http://40.129.74.199:8080/competency-framework/scorm/choosing-an-lms + + + SCORM Choosing an LMS + + + Video set helping people choose the right LMS. + + + + + 1.0 + + + Advanced Distributed Learning + + LOMv1.0 + publisher + + + + + + LOMv1.0 + yes + + + Creative Commons Attribution 3.0 Unported license, http://creativecommons.org/licenses/by/3.0/ + + + + 2013-11-19 + + + ADL has created a set of videos helping people choose an LMS. + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part1 + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part2 + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part3 + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part4 + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part5 + + diff --git a/competency-framework/xapi/tetris.xml b/competency-framework/xapi/tetris.xml index 5b6476c..815cca7 100644 --- a/competency-framework/xapi/tetris.xml +++ b/competency-framework/xapi/tetris.xml @@ -1,16 +1,16 @@ - URI - http://12.109.40.34/competency-framework/xapi/tetris + http://40.129.74.199:8080/competency-framework/xapi/tetris Experience API Tetris Master @@ -50,21 +50,21 @@ URI - http://12.109.40.34/competency/xapi/tetris/levels + http://40.129.74.199:8080/competency/xapi/tetris/levels URI - http://12.109.40.34/competency/xapi/tetris/score + http://40.129.74.199:8080/competency/xapi/tetris/score URI - http://12.109.40.34/competency/xapi/tetris/time + http://40.129.74.199:8080/competency/xapi/tetris/time URI - http://12.109.40.34/competency/xapi/tetris/lines + http://40.129.74.199:8080/competency/xapi/tetris/lines diff --git a/competency/computer-science/case-statements.xml b/competency/computer-science/case-statements.xml new file mode 100644 index 0000000..67a6fb6 --- /dev/null +++ b/competency/computer-science/case-statements.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/case-statements + + + Case Statements + + + Exhibits an understanding of case statements + + + + diff --git a/competency/computer-science/for-loop.xml b/competency/computer-science/for-loop.xml new file mode 100644 index 0000000..f1bd4c7 --- /dev/null +++ b/competency/computer-science/for-loop.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/for-loop + + + For Loops + + + Exhibits an understanding of for loops and their uses. + + + + diff --git a/competency/computer-science/if-else.xml b/competency/computer-science/if-else.xml new file mode 100644 index 0000000..724a8a8 --- /dev/null +++ b/competency/computer-science/if-else.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/if-else + + + If Else Blocks + + + Exhibits an understanding of if-else blocks and their uses. + + + + diff --git a/competency/computer-science/understanding-functions.xml b/competency/computer-science/understanding-functions.xml new file mode 100644 index 0000000..4cd6e91 --- /dev/null +++ b/competency/computer-science/understanding-functions.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-functions + + + Understanding Functions + + + Exhibits an understanding of functions and their uses. + + + + diff --git a/competency/computer-science/understanding-variables.xml b/competency/computer-science/understanding-variables.xml new file mode 100644 index 0000000..3edf54c --- /dev/null +++ b/competency/computer-science/understanding-variables.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/understanding-variables + + + Understanding Variables + + + Exhibits an understanding of variables and their uses. + + + + diff --git a/competency/computer-science/while-loop.xml b/competency/computer-science/while-loop.xml new file mode 100644 index 0000000..cbc69f0 --- /dev/null +++ b/competency/computer-science/while-loop.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/computer-science/while-loop + + + While Loops + + + Exhibits an understanding of while loops and their uses. + + + + diff --git a/competency/scorm/choosing-an-lms/part1.xml b/competency/scorm/choosing-an-lms/part1.xml new file mode 100644 index 0000000..213244e --- /dev/null +++ b/competency/scorm/choosing-an-lms/part1.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part1 + + + Choosing an LMS - part 1 + + + First part of the Choosing an LMS series. + + + + diff --git a/competency/scorm/choosing-an-lms/part2.xml b/competency/scorm/choosing-an-lms/part2.xml new file mode 100644 index 0000000..a9cd504 --- /dev/null +++ b/competency/scorm/choosing-an-lms/part2.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part2 + + + Choosing an LMS - part 2 + + + Second part of the Choosing an LMS series. + + + + diff --git a/competency/scorm/choosing-an-lms/part3.xml b/competency/scorm/choosing-an-lms/part3.xml new file mode 100644 index 0000000..4d69658 --- /dev/null +++ b/competency/scorm/choosing-an-lms/part3.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part3 + + + Choosing an LMS - part 3 + + + Third part of the Choosing an LMS series. + + + + diff --git a/competency/scorm/choosing-an-lms/part4.xml b/competency/scorm/choosing-an-lms/part4.xml new file mode 100644 index 0000000..85885a1 --- /dev/null +++ b/competency/scorm/choosing-an-lms/part4.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part4 + + + Choosing an LMS - part 4 + + + Fourth part of the Choosing an LMS series. + + + + diff --git a/competency/scorm/choosing-an-lms/part5.xml b/competency/scorm/choosing-an-lms/part5.xml new file mode 100644 index 0000000..6d84883 --- /dev/null +++ b/competency/scorm/choosing-an-lms/part5.xml @@ -0,0 +1,25 @@ + + + + + URI + http://40.129.74.199:8080/competency/scorm/choosing-an-lms/part5 + + + Choosing an LMS - part 5 + + + Fifth part of the Choosing an LMS series. + + + + diff --git a/competency/xapi/tetris/levels.xml b/competency/xapi/tetris/levels.xml index 12f1688..75c96a3 100644 --- a/competency/xapi/tetris/levels.xml +++ b/competency/xapi/tetris/levels.xml @@ -1,26 +1,26 @@ - - - - - URI + + + + + URI - http://12.109.40.34/competency/xapi/tetris/levels - - - Experience API Tetris Level Competency - - - Able to pass an acceptable number of levels. - + http://40.129.74.199:8080/competency/xapi/tetris/levels + + + Experience API Tetris Level Competency + + + Able to pass an acceptable number of levels. + - - + + diff --git a/competency/xapi/tetris/lines.xml b/competency/xapi/tetris/lines.xml index fbbaa03..c6886ac 100644 --- a/competency/xapi/tetris/lines.xml +++ b/competency/xapi/tetris/lines.xml @@ -1,26 +1,26 @@ - - - - - URI + + + + + URI - http://12.109.40.34/competency/xapi/tetris/lines - - - Experience API Tetris Line Competency - - - Able to pass an acceptable number of lines. - + http://40.129.74.199:8080/competency/xapi/tetris/lines + + + Experience API Tetris Line Competency + + + Able to pass an acceptable number of lines. + - - + + diff --git a/competency/xapi/tetris/points-per-minute.xml b/competency/xapi/tetris/points-per-minute.xml index 14cc8cf..bfa00b4 100644 --- a/competency/xapi/tetris/points-per-minute.xml +++ b/competency/xapi/tetris/points-per-minute.xml @@ -1,26 +1,26 @@ - - - - - URI + + + + + URI - http://12.109.40.34/competency/xapi/tetris/points-per-minute - - - Experience API Tetris Points per Minute Competency - - - Able to pass an acceptable number of points per minute. - + http://40.129.74.199:8080/competency/xapi/tetris/points-per-minute + + + Experience API Tetris Points per Minute Competency + + + Able to pass an acceptable number of points per minute. + - - + + diff --git a/competency/xapi/tetris/score.xml b/competency/xapi/tetris/score.xml index a907a18..3293303 100644 --- a/competency/xapi/tetris/score.xml +++ b/competency/xapi/tetris/score.xml @@ -1,26 +1,26 @@ - - - - - URI + + + + + URI - http://12.109.40.34/competency/xapi/tetris/score - - - Experience API Tetris Score Competency - - - Able to pass an acceptable score. - + http://40.129.74.199:8080/competency/xapi/tetris/score + + + Experience API Tetris Score Competency + + + Able to pass an acceptable score. + - - + + diff --git a/competency/xapi/tetris/time.xml b/competency/xapi/tetris/time.xml index 956ac24..9d0be52 100644 --- a/competency/xapi/tetris/time.xml +++ b/competency/xapi/tetris/time.xml @@ -1,26 +1,26 @@ - - - - - URI + + + + + URI - http://12.109.40.34/competency/xapi/tetris/time - - - Experience API Tetris Time Competency - - - Able to pass an acceptable length of time. - + http://40.129.74.199:8080/competency/xapi/tetris/time + + + Experience API Tetris Time Competency + + + Able to pass an acceptable length of time. + - - + + diff --git a/js/xapi-youtube-statements.js b/js/xapi-youtube-statements.js new file mode 100644 index 0000000..979c543 --- /dev/null +++ b/js/xapi-youtube-statements.js @@ -0,0 +1,122 @@ +(function(ADL){ + + var debug = true; + var log = function(message) + { + if (!debug) return false; + try + { + console.log(message); + return true; + } + catch(e) { return false; } + } + + XAPIYoutubeStatements = function() { + + var actor = {"mbox":"mailto:anon@example.com", "name":"anonymous"}; + var videoActivity = {}; + + this.changeConfig = function(options) { + actor = options.actor; + videoActivity = options.videoActivity; + } + + this.onPlayerReady = function(event) { + var message = "yt: player ready"; + log(message); + ADL.XAPIYoutubeStatements.onPlayerReadyCallback(message); + } + + this.onStateChange = function(event) { + var curTime = player.getCurrentTime().toString(); + var ISOTime = "PT" + curTime.slice(0, curTime.indexOf(".")+3) + "S"; + var stmt = null; + var e = ""; + switch(event.data) { + case -1: + e = "unstarted"; + log("yt: " + e); + break; + case 0: + e = "ended"; + log("yt: " + e); + stmt = completeVideo(ISOTime); + break; + case 1: + e = "playing"; + log("yt: " + e); + stmt = playVideo(ISOTime); + break; + case 2: + e = "paused"; + log("yt: " + e); + stmt = pauseVideo(ISOTime); + break; + case 3: + e = "buffering"; + log("yt: " + e); + break; + case 5: + e = "cued"; + log("yt: " + e); + break; + default: + } + ADL.XAPIYoutubeStatements.onStateChangeCallback(e, stmt); + } + + function buildStatement(stmt) { + var stmt = stmt; + stmt.actor = actor; + stmt.object = videoActivity; + return stmt; + } + + function playVideo(ISOTime) { + var stmt = {}; + /*if (competency) { + stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}}; + }*/ + + if (ISOTime == "PT0S") { + stmt.verb = ADL.verbs.launched; + } else { + stmt.verb = ADL.verbs.resumed; + stmt.result = {"extensions":{"resultExt:resumed":ISOTime}}; + } + return buildStatement(stmt); + } + + function pauseVideo(ISOTime) { + var stmt = {}; + + stmt.verb = ADL.verbs.suspended; + stmt.result = {"extensions":{"resultExt:paused":ISOTime}}; + + /*if (competency) { + stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}}; + }*/ + return buildStatement(stmt); + } + + function completeVideo(ISOTime) { + var stmt = {}; + + stmt.verb = ADL.verbs.completed; + stmt.result = {"duration":ISOTime, "completion": true}; + + /*if (competency) { + stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}}; + }*/ + return buildStatement(stmt); + } + + } + + ADL.XAPIYoutubeStatements = new XAPIYoutubeStatements(); + + ADL.XAPIYoutubeStatements.onPlayerReadyCallback = function(message) {}; + ADL.XAPIYoutubeStatements.onStateChangeCallback = function(stmt) {}; + +}(window.ADL = window.ADL || {})); diff --git a/js/xapipopcorn.js b/js/xapipopcorn.js index 15e7a7d..d9f6cc6 100644 --- a/js/xapipopcorn.js +++ b/js/xapipopcorn.js @@ -1,6 +1,6 @@ (function(ADL){ - var debug = false; + var debug = true; var log = function(message) { if (!debug) return false; @@ -10,6 +10,20 @@ return true; } catch(e){return false;} + } + + function getcomps(comp) { + if (comp) { + if (comp instanceof Array){ + var ret = []; + for(var i = 0; i < comp.length; i++){ + ret.push({"id": comp[i]}) + } + return ret; + } + return [{"id": comp}]; + } + return []; } function PopcornVideo(player, comp) { @@ -18,16 +32,27 @@ var firstQuartileHit = false; var halfwayHit = false; var thirdQuartileHit = false; + var ended = false; var isTracking = true; - var competency = comp; + var comparray = getcomps(comp); + var hascompetency = comp; // Youtube videos don't have children - var objectURI = player.media.children[0].src ? player.media.children[0].src : player.media.src; - var videoActivity = {"id":objectURI, "definition":{"name": {"en-US":playerID}}}; + var objectURI = "act:unknown"; + if (player.media.children) { + objectURI = player.media.children[0].src + } + else { + objectURI = player.media.src; + } + var videoActivity = {"id":objectURI, "definition":{"name": {"en-US":playerID}}}; + // Edit the actor inside of the wrapper or just include it here - var actor = ADL.XAPIWrapper.lrs.actor ? ADL.XAPIWrapper.lrs.actor : + var getactor = function() { + return ADL.XAPIWrapper.lrs.actor ? ADL.XAPIWrapper.lrs.actor : {"account":{"name":"tester", "homePage":"uri:testaccount"}}; + }; // Play event myplayer.on("play", function(){ @@ -45,6 +70,7 @@ // Normal start when vid is launched else{ log('video ' + playerID + ' launched') + ended = false; startstuff(true) } }); @@ -104,9 +130,9 @@ }); function startstuff(launched){ - var stmt = {"actor":actor, "object": videoActivity} - if (competency){ - stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}} + var stmt = {"actor":getactor(), "object": videoActivity} + if (hascompetency){ + stmt["context"] = {"contextActivities":{"other" : comparray}} } if (launched){ @@ -121,20 +147,20 @@ } function middleStuff(quartile, benchTime) { - var benchObj = {"id":objectURI + "#" + quartile, "definition":{"name":{"en-US":playerID + "#" + quartile}}}; + var benchObj = {"id":objectURI + "#" + quartile}; var bench = "PT" + benchTime + "S"; var extKey = "resultExt:" + quartile var result = {"extensions":{}}; - var stmt = {"actor":actor, + var stmt = {"actor":getactor(), "verb":ADL.verbs.progressed, "object":benchObj, "result":result} var context = {"contextActivities":{"parent":[{"id": objectURI}]}}; - if (competency){ - context["contextActivities"]["other"] = [{"id": "compID:" + competency}] + if (hascompetency){ + context["contextActivities"]["other"] = comparray; } stmt["context"] = context result["extensions"][extKey] = bench @@ -143,45 +169,71 @@ function pauseStuff(pauseTime){ var paused = "PT" + pauseTime + "S"; - var stmt = {"actor":actor, + var stmt = {"actor":getactor(), "verb":ADL.verbs.suspended, "object":videoActivity, "result":{"extensions":{"resultExt:paused":paused}}} - if (competency){ - stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}} + if (hascompetency){ + stmt["context"] = {"contextActivities":{"other" : comparray}} } report(stmt); } function seekStuff(seekTime){ var seeked = "PT" + seekTime + "S"; - var stmt = {"actor":actor, + var stmt = {"actor":getactor(), "verb":ADL.verbs.interacted, "object":videoActivity, "result":{"extensions":{"resultExt:seeked": seeked}}} - if (competency){ - stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}} + if (hascompetency){ + stmt["context"] = {"contextActivities":{"other" : comparray}} } report(stmt); } function endStuff(endTime) { + if (ended) return; + ended = true; var duration = "PT" + Math.round(endTime) + "S"; - var stmt = {"actor":actor, + var stmt = {"actor":getactor(), "verb":ADL.verbs.completed, "object":videoActivity, "result":{"duration":duration, "completion": true}} - if (competency){ - stmt["context"] = {"contextActivities":{"other" : [{"id": "compID:" + competency}]}} + if (hascompetency){ + stmt["context"] = {"contextActivities":{"other" : comparray}}; + + var stmtpassed = {"actor":getactor(), + "verb":ADL.verbs.passed, + "object":videoActivity, + "result":{"duration":duration, "completion": true}, + "context":{"contextActivities":{"other" : comparray}}} + multireport([stmt, stmtpassed], function(r){console.log(r)}); } - report(stmt); + else { + report(stmt); + } // Reset video quartile states firstQuartileHit = halfwayHit = thirdQuartileHit = false; } + this.multireport = multireport; + function multireport (stmt, callback) { + if (stmt) { + for(var i = 0; i < stmt.length; i++) + stmt[i]['timestamp'] = (new Date()).toISOString(); + if (isTracking) { + ADL.XAPIWrapper.sendStatements(stmt, callback); + } + else { + log("would send this statement if 'isTracking' was true."); + log(stmt); + } + } + } + this.report = report; function report (stmt) { if (stmt) { @@ -233,4 +285,4 @@ ADL.XAPIVideo = new XAPIVideo(); -}(window.ADL = window.ADL || {})); \ No newline at end of file +}(window.ADL = window.ADL || {})); diff --git a/js/xapiwrapper.js b/js/xapiwrapper.js index 328bd7d..06bf666 100644 --- a/js/xapiwrapper.js +++ b/js/xapiwrapper.js @@ -32,7 +32,7 @@ if ( !Date.prototype.toISOString ) { var Config = function() { var conf = {}; - conf['endpoint'] = "http://localhost:8000/xapi/"; + conf['endpoint'] = "https://lrs.adlnet.gov/xapi/"; try { conf['auth'] = "Basic " + Base64.encode('tom:1234'); diff --git a/main.py b/main.py index 6e60c42..f12ab97 100644 --- a/main.py +++ b/main.py @@ -2,9 +2,11 @@ from bottle import run, request, response, redirect, template import json import base64 +import urllib import requests import util from util import settings +from util import performance from pymongo import MongoClient from beaker.middleware import SessionMiddleware from werkzeug.security import generate_password_hash, check_password_hash @@ -16,7 +18,7 @@ } app = SessionMiddleware(bottle.app(), session_opts) - + mongo = MongoClient() db = mongo.compapp @@ -24,10 +26,25 @@ def send_js(filename): return static_file(filename, root='./js', mimetype='text/javascript') +@bottle.route('/static/badges/') +def server_static(filename): + return static_file(filename, root='./static/badges') + @bottle.route('/', method='GET') -@bottle.route('/', method='POST') def index(): s = request.environ.get('beaker.session') + username = s.get('username', None) + + return template('./templates/index', username=username, error=None) + +@bottle.route('/all_comps', method='POST') +@bottle.get('/all_comps', method='GET') +def all_comps(): + s = request.environ.get('beaker.session') + username = s.get('username',None) + if not username: + redirect('/') + form_fwkurl = request.forms.get('frameworkurl', None) knownframeworkurls = set() @@ -36,9 +53,32 @@ def index(): for url in knownframeworkurls: util.getComp(url) - username = s.get('username', None) - num_user_comps = len(util.getMyComps(username)) - return template('./templates/index', fwks=util.getAllSystemComps(), username=username, comps=num_user_comps, error=None) + return template('./templates/all_comps.tpl', fwks=util.getAllSystemComps(), username=username) + +@bottle.get('/add-framework/') +def add_framework(fwk): + s = request.environ.get('beaker.session') + username = s.get('username',None) + if not username: + redirect('/') + + to_add = fwk + if to_add == "tetris": + util.getComp("http://40.129.74.199:8080/competency-framework/xapi/tetris") + elif to_add == "choosinganlms": + util.getComp("http://40.129.74.199:8080/competency-framework/scorm/choosing-an-lms") + elif to_add == "basicprogramming": + util.getComp("http://40.129.74.199:8080/competency-framework/computer-science/basic-programming") + + return template('./templates/all_comps.tpl', fwks=util.getAllSystemComps(), username=username) + +@bottle.get('/badges') +def badges(): + perfwk = db.perfwk.find_one({"entry":"http://40.129.74.199:8080/performance-framework/xapi/tetris"}) + if not perfwk: + return template('./templates/badges', fwk={}, error="Tetris badges not found") + + return template('./templates/badges.tpl', fwk=perfwk, error="") @bottle.get('/login') def getlogin(): @@ -53,26 +93,26 @@ def postlogin(): s = request.environ.get('beaker.session') username = request.forms.get('username', None) pwd = request.forms.get('password', None) - + if not username or not pwd: return template('./templates/login', error="Username or password was missing") - + users = db.users user = users.find_one({"username":username}) - + if user: if not check_password_hash(user['pwd'], pwd): return template('./templates/login', error="Username exists and password didn't match") else: email = request.forms.get('email', None) name = request.forms.get('name', None) - + if not email or not name: return template('./templates/login', error="Email or name was missing") - + if not email.startswith("mailto:"): email = "mailto:%s" % email - users.insert({"username":username, "pwd": generate_password_hash(pwd), + users.insert({"username":username, "pwd": generate_password_hash(pwd), "email":email, "name":name}) s['username'] = username s.save() @@ -90,29 +130,90 @@ def getlogout(): def me(): s = request.environ.get('beaker.session') username = s.get('username',None) - if not username: + if not username: redirect('/login') theid = request.params.get('uri', None) + my_badges = False + if theid: c = util.getComp(theid, user=username) - return template('./templates/comp', username=username, fwk=c) + + if theid == "http://40.129.74.199:8080/competency-framework/xapi/tetris": + my_badges = True + return template('./templates/comp', username=username, fwk=c, my_badges=my_badges) mycomps = util.getMyComps(username) return template('./templates/me', fwks=mycomps, username=username, error=None) +@bottle.route('/mybadges') +def my_badges(): + s = request.environ.get('beaker.session') + username = s.get('username',None) + if not username: + redirect('/login') + + perfwk = db.perfwk.find_one({"entry":"http://40.129.74.199:8080/performance-framework/xapi/tetris"}) + levels = lines = scores = times = total = 0 + for component in perfwk["components"]: + if component["id"] == "comp_levels": + for pl in component["performancelevels"]: + levels += 1 + elif component["id"] == "comp_lines": + for pl in component["performancelevels"]: + lines += 1 + elif component["id"] == "comp_scores": + for pl in component["performancelevels"]: + scores += 1 + else: + for pl in component["performancelevels"]: + times += 1 + total = levels + lines + scores + times + + + performance.updatePerformance(settings.PERFORMANCE_FWKS["tetris"], username) + comps = util.getComp("http://40.129.74.199:8080/competency-framework/xapi/tetris", username) + + my_levels = my_lines = my_scores = my_times = my_total = 0 + for competency in comps["competencies"]: + if competency["title"] == "Experience API Tetris Level Competency": + if 'performances' in competency: + for perf in competency["performances"]: + my_levels += 1 + elif competency["title"] == "Experience API Tetris Line Competency": + if 'performances' in competency: + for perf in competency["performances"]: + my_lines += 1 + elif competency["title"] == "Experience API Tetris Score Competency": + if 'performances' in competency: + for perf in competency["performances"]: + my_scores += 1 + else: + if 'performances' in competency: + for perf in competency["performances"]: + my_times += 1 + my_total = my_levels + my_lines + my_scores + my_times + + return template('./templates/mybadges', comps=comps, total=total, my_total=my_total, levels=levels, lines=lines, scores=scores, times=times, my_levels=my_levels, my_lines=my_lines, + my_scores=my_scores, my_times=my_times) + @bottle.post('/update') def updatecomp(): s = request.environ.get('beaker.session') username = s.get('username',None) - if not username: + if not username: redirect('/login') endpoint = request.forms.get('endpoint', None) auth = "Basic %s" % base64.b64encode("%s:%s" % (request.forms.get('name', None), request.forms.get('password', None))) fwkid = request.forms.get('fwkid', None) - + c = util.getComp(fwkid, user=username) util.updateCompFwkStatus(username, c, endpoint+"statements", auth) - return template('./templates/comp', username=username, fwk=c) + + my_badges = False + if fwkid == "http://40.129.74.199:8080/competency-framework/xapi/tetris": + my_badges = True + + return template('./templates/comp', username=username, fwk=c, my_badges=my_badges) @bottle.get('/test') def gettest(): @@ -120,25 +221,45 @@ def gettest(): username = s.get('username',None) if not username: redirect('/login') + fwkid = request.params.get('fwkid', None) theid = request.params.get('compid', None) + print theid + print fwkid if not theid and not fwkid: redirect('/') - - # because this is a demo, we pick with framework we can + + # because this is a demo, we pick with framework we can # do a LR lookup on - if fwkid == 'http://adlnet.gov/competency-framework/scorm/choosing-an-lms': + if fwkid == 'http://40.129.74.199:8080/competency-framework/scorm/choosing-an-lms': user = db.users.find_one({"username":username}) actor = {'mbox':user['email'], 'name':user['name']} urls = util.getContentURLsFromLR(theid) + #endpoint = settings.LRS_STATEMENT_ENDPOINT + #auth = settings.AUTHORIZATION if urls: return template('./templates/videolist.tpl', user=username, compid=theid, actor=json.dumps(actor), urls=urls) + + if theid == 'http://40.129.74.199:8080/competency/computer-science/understanding-variables': + return template('./templates/understanding-variables.tpl', compid=theid, fwkid=fwkid, user=username) + elif theid == 'http://40.129.74.199:8080/competency/computer-science/case-statements': + return template('./templates/case-statements.tpl', compid=theid, fwkid=fwkid, user=username) + elif theid == 'http://40.129.74.199:8080/competency/computer-science/if-else': + return template('./templates/if-else.tpl', compid=theid, fwkid=fwkid, user=username) + elif theid == 'http://40.129.74.199:8080/competency/computer-science/for-loop': + return template('./templates/for-loop.tpl', compid=theid, fwkid=fwkid, user=username) + elif theid == 'http://40.129.74.199:8080/competency/computer-science/while-loop': + return template('./templates/while-loop.tpl', compid=theid, fwkid=fwkid, user=username) + elif theid == 'http://40.129.74.199:8080/competency/computer-science/understanding-functions': + return template('./templates/understanding-functions.tpl', compid=theid, fwkid=fwkid, user=username) + return template('./templates/test.tpl', compid=theid, fwkid=fwkid, user=username) @bottle.post('/test') def posttest(): fwkid = request.forms.get('fwkid') theid = request.forms.get('compid') + testname = request.params.get('testname') s = request.environ.get('beaker.session') username = s.get('username',None) if not username: @@ -148,52 +269,53 @@ def posttest(): if not user: redirect('/login') + actor = {'mbox':user['email'], 'name':user['name']} + questions = [] + answers = [] + types = [] + responses = [] + + for x in range(1,6): + questions.append(request.forms.get('questionasked' + str(x))) + answers.append(request.forms.get('answer' + str(x))) + types.append(request.forms.get('type' + str(x))) + responses.append(request.forms.get('question' + str(x))) + + test_name = 'activity:%s_quiz' % testname + display_name = urllib.unquote_plus(testname) + ' quiz' - # here would be some sort of evaluation - evaluated = request.forms.get('evaluated', False) - - if not evaluated: - data = { - 'actor': actor, - 'verb': {'id': 'http://adlnet.gov/expapi/verbs/passed', 'display':{'en-US': 'passed'}}, - 'object':{'id': 'some:activity_id_foo'}, - 'context':{'contextActivities':{'other':[{'id':theid}]}} - } - post_resp = requests.post(settings.LRS_STATEMENT_ENDPOINT, data=json.dumps(data), headers=settings.HEADERS, verify=False) - - query_string = '?verb={0}&activity={1}&related_activities={2}'.format('http://adlnet.gov/expapi/verbs/passed', theid, 'true') - get_resp = requests.get(settings.LRS_STATEMENT_ENDPOINT + query_string , headers=settings.HEADERS, verify=False) - - results = json.loads(get_resp.content) - stmt_results = results['statements'] + wrong, data = util.get_result_statements(responses, answers, types, questions, actor, test_name, display_name, fwkid, theid) + post_resp = requests.post(settings.LRS_STATEMENT_ENDPOINT, data=json.dumps(data), headers=settings.HEADERS, verify=False) + status = post_resp.status_code + content = post_resp.content + + stmt_results = util.retrieve_statements(status, content, theid, actor) achieved = False - for stmt in stmt_results: - if 'context' in stmt: - if 'contextActivities' in stmt['context']: - if 'other' in stmt['context']['contextActivities']: - for acts in stmt['context']['contextActivities']['other']: - if theid in acts['id']: - achieved = True - break + latest_attempt = stmt_results[0] + + if latest_attempt["verb"]["id"] == "http://adlnet.gov/expapi/verbs/passed": + achieved = True if achieved: - achieved_data = { - 'actor': {'mbox':user['email'], 'name':user['name']}, - 'verb': {'id': 'http://adlnet.gov/expapi/verbs/achieved', 'display':{'en-US': 'achieved'}}, - 'object':{'id': theid}, - 'context':{'contextActivities':{'parent':[{'id':fwkid}]}} - } - post_resp = requests.post(settings.LRS_STATEMENT_ENDPOINT, data=json.dumps(achieved_data), headers=settings.HEADERS, verify=False) util.setAchievement(theid, username) - return "

ok %s

Your progress has been recorded. Back to list" % theid + + return template('./templates/results', theid=theid, passed=achieved) @bottle.get('/admin/reset') def reset(): s = request.environ.get('beaker.session') s.invalidate() mongo.drop_database(db) + util.parsePerformanceFwk() redirect('/') - -run(app, host='localhost', port=8888, reloader=True) \ No newline at end of file + +@bottle.get('/admin') +def reset(): + return template('./templates/admin.tpl') + + +if __name__ == '__main__': + util.parsePerformanceFwk() + run(app, host='0.0.0.0', port=8888, server='gunicorn') diff --git a/performance-framework/xapi/tetris.xml b/performance-framework/xapi/tetris.xml index 227c759..86904c2 100644 --- a/performance-framework/xapi/tetris.xml +++ b/performance-framework/xapi/tetris.xml @@ -1,5 +1,5 @@ - URI - http://12.109.40.34/performance-framework/xapi/tetris + http://40.129.74.199:8080/performance-framework/xapi/tetris @@ -29,7 +29,7 @@ - + text/html @@ -53,12 +53,12 @@ Passed an impressive amount of levels - + application/xml - + application/xml @@ -107,12 +107,12 @@ Made a bunch of lines. - + application/xml - + application/xml @@ -170,12 +170,12 @@ Worthy score. - + application/xml - + application/xml @@ -260,12 +260,12 @@ Played for a long time. - + application/xml - + application/xml diff --git a/requirements.txt b/requirements.txt index 94204a7..58eec7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ pymongo==2.6.3 pyquery==1.2.6 requests==2.0.1 wsgiref==0.1.2 +gunicorn==18.0 \ No newline at end of file diff --git a/scorm/choosing-an-lms/part1.html b/scorm/choosing-an-lms/part1.html index 424cd8b..09f9f31 100644 --- a/scorm/choosing-an-lms/part1.html +++ b/scorm/choosing-an-lms/part1.html @@ -10,22 +10,22 @@ - - - + + + - - - + + + - diff --git a/scorm/choosing-an-lms/part2.html b/scorm/choosing-an-lms/part2.html index 1ddc3ed..905ab2e 100644 --- a/scorm/choosing-an-lms/part2.html +++ b/scorm/choosing-an-lms/part2.html @@ -10,22 +10,22 @@ - - - + + + - - - + + + - diff --git a/scorm/choosing-an-lms/part3.html b/scorm/choosing-an-lms/part3.html index f0ec18b..0b4113b 100644 --- a/scorm/choosing-an-lms/part3.html +++ b/scorm/choosing-an-lms/part3.html @@ -10,22 +10,22 @@ - - - + + + - - - + + + - diff --git a/scorm/choosing-an-lms/part4.html b/scorm/choosing-an-lms/part4.html index 944ed98..ae62374 100644 --- a/scorm/choosing-an-lms/part4.html +++ b/scorm/choosing-an-lms/part4.html @@ -10,22 +10,22 @@ - - - + + + - - - + + + - diff --git a/scorm/choosing-an-lms/part5.html b/scorm/choosing-an-lms/part5.html index 54c71e1..37eb213 100644 --- a/scorm/choosing-an-lms/part5.html +++ b/scorm/choosing-an-lms/part5.html @@ -10,22 +10,22 @@ - - - + + + - - - + + + - diff --git a/static/badges/lines_100.png b/static/badges/lines_100.png new file mode 100755 index 0000000..475494c Binary files /dev/null and b/static/badges/lines_100.png differ diff --git a/static/badges/lines_20.png b/static/badges/lines_20.png new file mode 100755 index 0000000..00f7ebf Binary files /dev/null and b/static/badges/lines_20.png differ diff --git a/static/badges/lines_40.png b/static/badges/lines_40.png new file mode 100755 index 0000000..51e1b67 Binary files /dev/null and b/static/badges/lines_40.png differ diff --git a/static/badges/lines_60.png b/static/badges/lines_60.png new file mode 100755 index 0000000..e1bcd66 Binary files /dev/null and b/static/badges/lines_60.png differ diff --git a/static/badges/lines_80.png b/static/badges/lines_80.png new file mode 100755 index 0000000..3b72989 Binary files /dev/null and b/static/badges/lines_80.png differ diff --git a/static/badges/lvl_10.png b/static/badges/lvl_10.png new file mode 100755 index 0000000..08bfa8b Binary files /dev/null and b/static/badges/lvl_10.png differ diff --git a/static/badges/lvl_15.png b/static/badges/lvl_15.png new file mode 100755 index 0000000..67c5373 Binary files /dev/null and b/static/badges/lvl_15.png differ diff --git a/static/badges/lvl_20.png b/static/badges/lvl_20.png new file mode 100755 index 0000000..520200a Binary files /dev/null and b/static/badges/lvl_20.png differ diff --git a/static/badges/lvl_5.png b/static/badges/lvl_5.png new file mode 100755 index 0000000..078934b Binary files /dev/null and b/static/badges/lvl_5.png differ diff --git a/static/badges/minutes_12.png b/static/badges/minutes_12.png new file mode 100755 index 0000000..d5c0d03 Binary files /dev/null and b/static/badges/minutes_12.png differ diff --git a/static/badges/minutes_15.png b/static/badges/minutes_15.png new file mode 100755 index 0000000..d6d2e7e Binary files /dev/null and b/static/badges/minutes_15.png differ diff --git a/static/badges/minutes_3.png b/static/badges/minutes_3.png new file mode 100755 index 0000000..3c1fa6c Binary files /dev/null and b/static/badges/minutes_3.png differ diff --git a/static/badges/minutes_6.png b/static/badges/minutes_6.png new file mode 100755 index 0000000..0d925f7 Binary files /dev/null and b/static/badges/minutes_6.png differ diff --git a/static/badges/minutes_9.png b/static/badges/minutes_9.png new file mode 100755 index 0000000..83f0956 Binary files /dev/null and b/static/badges/minutes_9.png differ diff --git a/static/badges/points_100000.png b/static/badges/points_100000.png new file mode 100755 index 0000000..587f651 Binary files /dev/null and b/static/badges/points_100000.png differ diff --git a/static/badges/points_1000000.png b/static/badges/points_1000000.png new file mode 100755 index 0000000..1ff7005 Binary files /dev/null and b/static/badges/points_1000000.png differ diff --git a/static/badges/points_1500000.png b/static/badges/points_1500000.png new file mode 100755 index 0000000..3d670ac Binary files /dev/null and b/static/badges/points_1500000.png differ diff --git a/static/badges/points_200000.png b/static/badges/points_200000.png new file mode 100755 index 0000000..a6bda74 Binary files /dev/null and b/static/badges/points_200000.png differ diff --git a/static/badges/points_2000000.png b/static/badges/points_2000000.png new file mode 100755 index 0000000..6af1a54 Binary files /dev/null and b/static/badges/points_2000000.png differ diff --git a/static/badges/points_400000.png b/static/badges/points_400000.png new file mode 100755 index 0000000..543e5ff Binary files /dev/null and b/static/badges/points_400000.png differ diff --git a/static/badges/points_50000.png b/static/badges/points_50000.png new file mode 100755 index 0000000..5139f7e Binary files /dev/null and b/static/badges/points_50000.png differ diff --git a/static/badges/points_800000.png b/static/badges/points_800000.png new file mode 100755 index 0000000..e3e112e Binary files /dev/null and b/static/badges/points_800000.png differ diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 0000000..0382457 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,45 @@ +; Sample supervisor config file. + +[unix_http_server] +file=/tmp/supervisor.sock ; (the path to the socket file) +;chmod=0700 ; socket file mode (default 0700) +;chown=nobody:nogroup ; socket file uid:gid owner +;username=user ; (default is no username (open server)) +;password=123 ; (default is no password (open server)) + +;[inet_http_server] ; inet (TCP) server disabled by default +;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface) +;username=user ; (default is no username (open server)) +;password=123 ; (default is no password (open server)) + +[supervisord] +logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=false ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) + + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket +;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket +;username=chris ; should be same as http_username if set +;password=123 ; should be same as http_password if set +;prompt=mysupervisor ; cmd line prompt (default "supervisor") +;history_file=~/.sc_history ; use readline history if available + +; The below sample program section shows all possible program subsection values, +; create one or more 'real' program: sections to be able to control them under +; supervisor. + +[program:compapp] +command=python main.py ; the program (relative uses PATH, can take args) diff --git a/templates/admin.tpl b/templates/admin.tpl new file mode 100644 index 0000000..ccab4b2 --- /dev/null +++ b/templates/admin.tpl @@ -0,0 +1 @@ +Admin Reset diff --git a/templates/all_comps.tpl b/templates/all_comps.tpl new file mode 100644 index 0000000..54e6c53 --- /dev/null +++ b/templates/all_comps.tpl @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + +

+
+ +
+
+ Here are some frameworks you can add to the system: + +
+ My Competencies +
+
+ Below are the frameworks already added to the system. If you want to add one to your list, just click Go! +
+ %for fwk in fwks: +
+
+
+

{{fwk['title']}}

+
+
+

{{fwk['description']}}

+ %if username: +

Go

+ %end +
+
+
+ %end +
+
+ + \ No newline at end of file diff --git a/templates/badges.tpl b/templates/badges.tpl new file mode 100644 index 0000000..e7a3ae3 --- /dev/null +++ b/templates/badges.tpl @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + +
+ + %if error: +
{{error}}
+ %else: + %for component in fwk["components"]: +
+
+
+

{{component["id"]}}

+
+
+

{{component["title"]}}

+
+ %for pl in component["performancelevels"]: + %png = pl["id"] + ".png" + %tit = pl["id"].replace("_", " ") +

{{tit}} - {{pl["description"]}}

+ %end +
+
+
+ %end + %end +
+
+
+ + \ No newline at end of file diff --git a/templates/case-statements.tpl b/templates/case-statements.tpl new file mode 100644 index 0000000..acbccae --- /dev/null +++ b/templates/case-statements.tpl @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/templates/comp.tpl b/templates/comp.tpl index dc13178..ca6b0ab 100644 --- a/templates/comp.tpl +++ b/templates/comp.tpl @@ -15,7 +15,8 @@
@@ -26,32 +27,31 @@ Congrats! You've achieved all the competencies in this list!
%else: - %if username: - -
- -
- - -
-
-
- - -
-
- - -
- -
- %end + %if username: +
+ +
+ + + +
+ +
+ %end %end
+ %if my_badges: + My Tetris Badges +
+
+ + Play Tetris! +
+
+ All Badges + %else: %for comp in fwk['competencies']: %if comp['type'] == 'framework':
@@ -108,6 +108,7 @@
%end %end + %end
\ No newline at end of file diff --git a/templates/for-loop.tpl b/templates/for-loop.tpl new file mode 100755 index 0000000..a962d8c --- /dev/null +++ b/templates/for-loop.tpl @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/templates/if-else.tpl b/templates/if-else.tpl new file mode 100644 index 0000000..9c9a981 --- /dev/null +++ b/templates/if-else.tpl @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/templates/index.tpl b/templates/index.tpl index 879af8c..5b5a365 100644 --- a/templates/index.tpl +++ b/templates/index.tpl @@ -52,14 +52,6 @@ %end - Admin Reset -