GithubHelp home page GithubHelp logo

adlnet / xapiwrapper Goto Github PK

View Code? Open in Web Editor NEW
213.0 47.0 114.0 5.01 MB

Wrapper to simplify communication to an LRS

Home Page: https://adlnet.gov/projects/xapi/

License: Apache License 2.0

JavaScript 97.73% HTML 1.16% CSS 1.11%
xapi

xapiwrapper's People

Contributors

adl-trey avatar ajanderson1209 avatar bharatpareek avatar brian-learningpool avatar cr8onski avatar creighton avatar dependabot[bot] avatar ecointest avatar floriantolk avatar hsmith-adl avatar ioannap avatar jsma avatar ljwolford avatar neboduus avatar oliverfoster avatar pauliejes avatar rchadwic avatar rneatrour avatar ryanrolds avatar samthill avatar simis-trey avatar ty- avatar vbhayden avatar webb-nickj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xapiwrapper's Issues

Allow for a custom log function

Similar to how ADL.xhrRequestOnError is implemented.

currently log(), this.log() and ADL.XAPIWrapper.log() are the three ways log is being called. this should be limited.

Statement.Context can not be set

Hi All! I don't know if this is an issue or just under engineering, but Statement.Context can not be set. If I look at xapistatement.js I can see just some context references, but any Context Object. Is this normal? How could I use Context on statements?

Thanks

Library broken

Commit 0f0c4c0 broke the XAPIWrapper for me. AllI get from Chrome is:
Uncaught TypeError: Cannot read property 'log' of undefinedmergeRecursive @ xapiwrapper.js:1095getLRSObject @ xapiwrapper.js:1148XAPIWrapper @ xapiwrapper.js:111window.ADL @ xapiwrapper.js:1427(anonymous function) @ xapiwrapper.js:1429

Whereafter ADL.XAPIWrapper is not available.
The Problem seems to be that ADL.XAPIWrapper.log() is used before ADL.XAPIWrapper is registered.

Can you please fix that?

getStatements with attachments

getStatements always expects JSON back in the response, even for when using the attachments query. Is it worth discussing this a bit more to have it parse out the statement and do something with the attachments?

sendStatements() not functionally equivalent to sendStatement()?

I noticed while testing the ADL launch method that sendStatement() and sendStatements() are not functionally equivalent. For instance, while testing with Learning Locker v1, xAPI statements sent via sendStatements() would fail.

The same statements would succeed if used in a for-each call to sendStatement().

XAPI launch error with IE11

xapi_luanch_error_ie11

Test environment

  • xAPIWrapper 1.10.1
  • IE11

Error Message

{
    "description": "Object doesn't support this action",
    "number": -2146827843,
    "stack": "TypeError: Object doesn't support this action\n   at f (http://127.0.0.1:8099/lesson/6918064/xapiwrapper.min.js:2:30984)\n   at Anonymous function (http://127.0.0.1:8099/lesson/6918064/demo.html?xAPILaunchKey=abea8db9-da55-4dfa-82ec-98daa675259a&xAPILaunchService=http%3A%2F%2F127.0.0.1%3A8099%2F:22:8)\n   at j (http://127.0.0.1:8099/static/js/common/jquery.min.js:2:29992)\n   at Anonymous function (http://127.0.0.1:8099/static/js/common/jquery.min.js:2:30313)"
}

Launch problems with v0.9 TinCan launch

The Rustici launch mechanism passes through the mbox as an array rather than a string. I know the spec should be considered deprecated at this point but there do appear to be some popular learning management systems which still use this. See the comments at RusticiSoftware/launch#6 for background.

Security, username and password client-side

Isn't it a security risk to have the password to your LRS be sent client-side to be used with this library? I'm in the process of using this library to connect to our LRSs, but I'm a little confused at the security. Any insight would be greatly appreciated, thanks!

More URLs are not constructed properly

https://github.com/adlnet/xAPIWrapper/blob/master/xapiwrapper.js#L256

"Relative IRL that may be used to fetch more results, including the full path and optionally a query string but excluding scheme, host, and port. Empty string if there are no more results to fetch.

This IRL must be usable for at least 24 hours after it is returned by the LRS. In order to avoid the need to store these IRLs and associated query data, an LRS may include all necessary information within the IRL to continue the query, but should avoid generating extremely long IRLs. The consumer should not attempt to interpret any meaning from the IRL returned. "

So, it must be a relative URL and it must include the full path. Relative URLs (also called relative references or URL fragments) are not combined with a URL by concatenating them together, but by a special set of rules. For instance, combining http://a.example.com/stuff/orange with the relative reference alpha results in http://a.example.com/stuff/alpha . Combining http://a.example.com/stuff/orange with the relative reference /alpha results in http://a.example.com/alpha , and there are a variety of other rules as well. Since the more value is required to include the full path and not the hostname and scheme, the only legal sort of relative reference is one that starts with /, which will replace the whole URL path, not be concatenated to the end.

Auth param in url containing the "=" character

Hi,

While using xAPIWrapper, I encountered a little issue to get auth in the url. My authentication token ends with a "=" char. I found that if a parameter contain this char, it is not used. Maybe this should be modified.

Thanks,
Corentin

submit statement

submit statement returns an error "internal server error"
at the same time the statements are saved any clarification?

send state pass array is not array form one page to another page

Content-Type is application/json if state value is Array. But Content-Type is application/octet-stream if you pass Array form one page to another page . The reason is use instanceof to test state value .

see javascript-when-i-pass-array-from-iframe-function-the-array-lose-his-type

Test in chrome with windows 10.
t1. html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        function test() {
            var arr = [];
            arr.push(1);
            var r1 = arr instanceof Array;
            console.log("is array (instanceof) " + r1.toString());
            console.log("is array (Array.isArray) " + Array.isArray(arr))
            console.log("call iframe")
            window.f1.demo(arr);
        }
    </script>
</head>
<body>
<iframe src="t2.html" name="f1"  height="600" width="100%" frameborder="0" scrolling="no" onload="test()"></iframe>
</body>
</html>

t2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        demo = function (param) {
            var r1 = param instanceof Array;
            console.log("is array (instanceof) " +  r1.toString())
            console.log("is array (Array.isArray) " +  Array.isArray(param))
        }
    </script>
</head>
<body>
</body>
</html>

The consloe result

is array (instanceof) true
is array (Array.isArray) true
call iframe
is array (instanceof) false
is array (Array.isArray) true

ADL.launch not compatible with IE

Looks like the ADL.launch method makes use of the URL API which is not supported by IE. This means the current code cannot initialize the launch.

parseQueryString is not working properly if hashes appear after the search

The parseQueryString method in xAPIWrapper takes no account of hashes potentially appearing after the search paramters.

Something like this would overcome the problem:

function parseQueryString()
{
    var loc, qs, pairs, pair, ii, parsed;
    qs = window.location.search.substr(1);

    pairs = qs.split('&');
    parsed = {};
    for ( ii = 0; ii < pairs.length; ii++) {
        pair = pairs[ii].split('=');
        if (pair.length === 2 && pair[0]) {
            parsed[pair[0]] = decodeURIComponent(pair[1]);
        }
    }
    return parsed;
}

Sendind statement on IE10

Hi,

I'm using your library for some tests and I've get an issue :

ADL.XAPIWrapper.sendStatement(stmt);
this line works fine on Chrome, FF (latest versions) and IE11 ... but it doesn't work with IE10.

An exception is sent with message : "Error : Access denied".

Have I missed something, or is it a real bug ?

Thanks,
Corentin

funny conditional

This conditional bugs me. If the first part of the conditional is true, then the second part can't possible be false. Isn't the second part redundant? It is used several times in the documentation.
if (res.more && res.more !== "") ...

Development roadmap?

Hi adlnet,

I wonder what is the future roadmap for the xAPIWrapper? Are there any structural changes or extensions planned? We are starting to use this great lib as the base for our apps and tests so it would be good to know if important changes are ahead.

It would be fantastic to put this code under semantic versioning, this would make the integration and maintenance easier for app devs.

Thanks

console.warning()

Hi,

firstly, thanks for removing the alerts in ADL.XHR_request()
However I believe there is a syntax error in commit a998c356f6970b99e057da161deb2c7d356bfda0

Instead of console.warning() it should be console.warn(), see docs

Firebug is currently throwing an exception and stops logging:)
TypeError: console.warning is not a function

I might do a pull request. What is your preferred workflow in such cases? First an issue and then a pull request or a straight pull request?

Cheers

Implement as a RequireJS module if available

Rather than forcing the namespace this would let it work properly with modern good practices - there's various patterns, but basically if there's no define function defined then nothing changes, otherwise it should effectively have define(function(){return ADL;}) - but possibly without using the global namespace at all.

url extended param not pass to LRS

Hi
I use launch server and want to pass some param(ex: a=b&c=d) to launch url. But the xAPIWrapper.js is not pass extended param to LRS. I find #14 , it is delete pass param code. I do not know why? Anyone can help me

Sending statements with binary attachments is not supported

The current implementation for sending statements with attachments does not support sending binary data, for example an image or pdf. Currently the code uses strings to store / concat together the multipart/mixed request, to support sending binary data this would need to be update to use something like ArrayBuffers.

A few examples on "getting LRS statements."

Would it be possible to create a folder with several examples of pulling records from an LRS. Something like the following would be enormously helpful to what we are trying to accomplish in my company.

getStatements1.html
This would be an example of a getting LRS records. It would pull down all verbs with no data restrictions and no special formatting. It would look like a large data dump.

getStatements2.html
This would be an example of a getting LRS records but giving the user a way to specify what data they want. For example, I would like to be able sometimes to just grab Actor, verb, object, date/time and context activity (like category). It would also have a variable that can be adjusted that would allow for getting only a certain number of records.

getStatements3.html
This would be like getStatements2 but with additional features that would allow the user to limit data to a date range or a category name. It would also be parsed for a neat appearance.

Thank you very much for your consideration. ~ John M.

example.html - invalid auth data

            ADL.XAPIWrapper.changeConfig({
                'endpoint': 'https://lrs.adlnet.gov/xapi/',
                'user': 'steven',
                'password': 'test123'
            });

returns 401 UNAUTHORIZED

NPM module

Is this repo up on NPM? I'm not able to find it, it would be nice to npm install

Support for result object

I was using this JS to push h5p statements from Moodle to an LRS.

But the new ADL.XAPIStatement(), does not accept result parameter, the result paramenter can be used to send user's response to LRS.

For example answer to a quiz question.

Send multiple parameters for searchParams in getStatements

Not exactly an issue, but I cant find anything related to this in the documentation.

Suppose I want to query for multiple parameters like all statements with verbs pause or play.
Or all Users whose id(mail) is on a particular domain, etc. How do I do such queries? If possible please
direct to a complete documentation on the searchParams object as it looks quite essential.

Thanks.

Attachments assume a contentType of application/octet-stream

I noticed this while testing a PDF upload. Setting contentType: application/pdfon the attachment item it was still being set to application/octet-stream in the POST request. This caused the LRS (Learning Locker) to save the file as a .bin rather than .pdf.

Cross Domain and IE10

Hey
when I try to use this with IE10 (works great with ie11, chrome) I get an error:

SCRIPT5: Access is denied.
xapiwrapper.js, line 1342 character 13

This is the line it refers to:
xhr.open(ieModeRequest.method, ieModeRequest.url);

Any ideas how to fix this - having the course on a secure server makes no diffence.

Sorry - pressed submit before adding the error!

John

Statement id collision (UUID v4)

After generating about 5k statements across 40 devices (same model tablet) we encountered a id collision. JavaScript's Math.random() isn't that great of a PRNG and the Web Crypto API isn't widely supported yet. It may be better to use a v3/v5 UUID (hash versions) and use actor id + course id + activity + timestamp to produce UUIDs that are less likely to collide in this context.

If you're OK switching to v3 or v5 I'm happy to do the work.

400 Bad Request

I've been trying out the xAPIWrapper for the first time but I keep getting this error in the browser console (XXXXX refers to my endpoint ID):

cloud.scorm.com/tc/XXXXX/statements:1
POST 
https://cloud.scorm.com/tc/XXXXXX/statements 400 (Bad Request)

My authentication code is:

var conf = {
            "endpoint": "https://cloud.scorm.com/tc/XXXX/",
            "user": "XXXX",
            "password": "XXXXX"
        };
ADL.XAPIWrapper.changeConfig(conf);

I've used these same credentials with the tin can prototypes (http://tincanapi.com/prototypes/) and it works fine. Not sure what's going on?

having issue working with get more statements

I am facing issue processing more statements from XAPI. In my code below, I am using XAPI Wrapper and I am getting around 900 statements from lrs in rek, however, when I convert them into a collection and try to use the where clause, it does not give me any result.

Please Note: I can get the same thing done using fetchAllStatementes and it also works fine with getStatements (for only the first 100 records), however, I wish to do it manually using getMoreStatements.

Is there an example of merging statements using get more statements, creating a collection on top of it and then using the where query to filter the data?

My code:
var stmt1 = JSON.stringify({
"mbox": actor.mbox ,
"name": actor.name
});

var stmt2 = JSON.stringify({
	"mbox": "mailto:[email protected]"  
});

var stmtVerb = JSON.stringify({
	"id": "http://adlnet.gov/expapi/verbs/started"
});

var stmtCtx = JSON.stringify({
	"contextActivities": {
		"grouping": [
			{
				"id": competency.iri
			}
		]
	}
});

var search = ADL.XAPIWrapper.searchParams();
search['agent'] = stmt1;
search['authority'] = stmt2;
search['context'] = stmtCtx;
var rek = []
ADL.XAPIWrapper.getStatements(search, null,
   function getmore(r){
      var res = JSON.parse(r.response);
      $.each(res.statements, function(x,y){
        rek.push(y)  ;
      });
      
      if (res.more && res.more !== ""){
         ADL.XAPIWrapper.getStatements(search, res.more, getmore);
      }
   });

console.log(rek);

//var ret = ADL.XAPIWrapper.getStatements(search);	//works fine
//var statements = new ADL.Collection(ret.statements);  

var stmt = new ADL.Collection(rek);
var filtered_data = stmt.where('actor.name = "ccazabon"').exec(function(data){
					console.log(data);//no output-empty array, however, matching data does exists
				});

var p = [{'name': 'Steven', 'age': 25, 'dob':{
'mm': 'jan',
'dd': '18'
}},
{'name': 'John', 'age': 35, 'dob':{
'mm': 'feb',
'dd': '19'
}}];
//console.log(p);
var a = new ADL.Collection(p);
//console.log(a);
var d = a.where('dob.mm = "jan"').exec(function(data){console.log(data)});//works as expected

I think there is some issue with merging all the statements and creating the ADL.Collection, however, I am not getting any online help to resolve the same.
Your help is greatly appreciated.

sendActivityProfile function using If-Match and LearningLocker LRS

I have a question about the sendActivityProfile functiion. When passing an object as the profileval the function will always use the POST method.

Unfortunately, when using POST the LearningLocker LRS will ignore the If-Match header and will always store the data sent even if it overwrites an updated profile object. If I modify the code so that it uses PUT, LearningLocker behaves as expected and returns http status 412 - precondtion failed.

Just wondering what the correct behaviour here should be? Is this a fault with the wrapper or the LRS?

And what is the reason POST always being used when profileval is an object but not if profileval is an array? Of the top of my head I would expect POST when creating a new profile and PUT when updating an existing profile, why should the method be dependent on the profile data type?

using this API with IE10

Hi

I ran into a problem while using this API with IE10. The API was throwing invalid state error in IE 10 while trying to fetch statements from SCORM CLOUD. All works well in IE 11 and other browsers.

Debugging further I realized that the issue was actually with the xhr.withCredentials in the ADL.XHR_request function. Moving it after xhr.open fixed the issue. Is it possible to raise a pull request to include it in the code?

xhr.open(method, url, callback != null);
xhr.withCredentials = withCredentials;

or
if(typeof(withCredentials) != "undefined") // if Boolean is not passed for withCredentials
xhr.withCredentials = withCredentials;
xhr.open(method, url, callback != null);

toISOString is undefined

Uncaught TypeError: undefined is not a function

Came across this when working with the State API, it applies to any function using toISOString() which is defined in the top of xapiwrapper.js if the browser doesn't support the native function. I can call Date.prototype.toISOString in the console, but I cannot process any dates.

RangeError: Invalid time value

This bug has also brought to my attention leniency on the date string in the getStatements function. This will encodeURIComponent() any date string and the LRS will process it properly. e.g. 02/11/2015 11:04 AM will query https://lrs.adlnet.gov/xapi/statements?format=exact&since=02%2F11%2F2015%2011%3A04%20AM with results returned as if an ISO 8601 date was passed.

The xAPI spec is unclear as to whether timestamps MUST be ISO 8601 everywhere (statements, queries, database).

A timestamp MUST be formatted according to ISO 8601.

All for-in loops do not have checks for hasOwnProperty

Array.prototype.foo = function() {}
var statements = [ ... ];
xapiWrapper.sendStatements(statements, ...);
-> SyntaxError: Unexpected token u in JSON at position 0
    at JSON.parse (<anonymous>)
    at XAPIWrapper.prepareStatement
    at XAPIWrapper.sendStatements

Reason:

for (var key in statements) { console.log(key) }
-> 0
-> 1
-> 2
-> ...
-> foo
-> other prototype extensions...

callback for Errors in xhr_request

ADL.XHR_request() and callees: It would be nice to have the opportunity to submit an extra callback for errors. With the alerts removed in #26 (which is great!) we need an easy way to communicate errors to the users. Currently I am monkey-patching the XMLHttpRequest object to do this but that is not a good solution.

XHR callback not being fired on error

Running in to an issue when calling sendState(..., callback)/sendStatements(..., callback) the supplied callback is not invoked when an error is encountered (either the request is bad or the LRS is down). Looking through the code I see that a global error handler has been added, but that is not optimal as it doesn't easily facilitate context specific handling of the failure.

IMO, the expected behavior behavior is that the callback is invoked regardless of the outcome. It's up to the dev to inspect the status code (or an error object) and determine the correct course of action inside of the callback. Other platforms, like Node.js, have the first argument in callbacks be the error or null (if no error). That would require that callbacks confirm to function(error, response, body) where error is null when the request is successful.

Adding a option/flag to enable the expected behavior (the callback is always invoked regardless of outcome) would be a significant step towards correcting the problem. I'm willing to do the work of adding this option and behavior.

Invalid launch parameters

I got 'Invalid Launch Parameters' error while launching course build using adapt-authoring tool and tkhub xAPI plugin.

var wrapper;
ADL.launch(function(err, launchdata, xAPIWrapper) {
    if (!err) {
        wrapper = xAPIWrapper;
        console.log("--- content launched via xAPI Launch ---\n", wrapper.lrs, "\n", launchdata);
    } else {
       console.log(err);
    }
    $('#endpoint').text(wrapper.lrs.endpoint);
}, true);

How to provide launch parameter?

Why is there no ADL.activities object?

Since ADL.verbs exists, I'm just wondering why ADL.activities (or activityTypes) doesn't?

I'm using the xAPIWrapper in a project I'm working on and was surprised that it wasn't there.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.