LearningLocker / learninglocker

Learning Locker - The Open Source Learning Record Store. Started in 2014.
https://learningpool.com/solutions/learning-record-store-learning-locker/learning-locker-community-overview/
GNU General Public License v3.0
553 stars 274 forks source link

Cannot resume Articulate Storyline 2 course #699

Closed chadabaker closed 9 years ago

chadabaker commented 9 years ago

Version master at 33cca0f on 1.5.2 (from VERSION file ... downloaded release)

Steps to reproduce the bug

  1. Create working launch link to course
  2. Launch course and play through a bit
  3. Close course
  4. Re-launch course with same activity, actor, and registration
  5. See that course does not prompt for resume

Expected behaviour

  1. Course should prompt for resume

Actual behaviour As noted above, course does not prompt for resume

Server information MongoDb with BASIC authentication

Client information OS: Red Hat Enterprise Linux Server release 6.6 Browser: Chrome version 44.0.2403.89 beta-m

Additional information Testing the same course with other LRS platforms resulted in the course prompting the user to resume. This is true for ScormCloud and the Tin Can Prototypes endpoint that is publicly available. In both of these cases, I see the response from the StateAPI call (method=GET&state=resume) coming back with a Content-Type of "application/json". With Learning Locker / Laravel, the Content-Type for this response is "text/plain". Can't guarantee that the content-type is what's killing the resume functionality, but I don't see what else it could be.

chadabaker commented 9 years ago

The StateAPI method=PUT request payload:

agent=%7B%22name%22%3A%22First%20Last%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22https%3A%2F%2Fxxx%2Dxxxx%2Exxxxxx%2Exxx%22%2C%22name%22%3A%22custom%2Etap%2E1901%22%7D%7D&stateId=resume&registration=0301fcae%2D7f86%2D4688%2Dae3c%2D1d1ccd0346a6&Authorization=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&content=%7B%22data%22%3A%222o147060ji1001111a0101101111w101%5En5femaXcXzFm%2E5p1rdsD4DRB1%5E1%5E0o00a6001020000a60010200002000%22%7D&Content%2DType=application%2Fjson&activityId=http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1

The StateAPI method=GET response headers:

HTTP/1.1 200 OK Date: Fri, 17 Jul 2015 14:43:12 GMT Server: Apache Strict-Transport-Security: max-age=15768000 Updated: 2015-07-16T18:21:33+0000 ETag: "CB3E0D50F89BF019FDA4C8D04ED370BEA6DB867E" Cache-Control: private, must-revalidate X-Experience-API-Version: 1.0.1 Access-Control-Allow-Origin: https://xxx-xxxx.local Vary: Origin,Accept-Encoding Set-Cookie: laravel_session=eyJpdiI6IlhqVGFDNkJIVDZJVjZOTHBnQm9aSEwwaHBiUVUzaUNCWWQ4Y1FxTXJTUW89IiwidmFsdWUiOiJMQzR6Z0JSWEQrS0FRRTgwMWJhSUJWSVRRb0N4a1FFa2FUS015ZWl2SnB2Y1ZNMk5waHVRZndxQlNnSWpqaEhhS3lISUlYb2lQYlJGSHE2aHlXUkVDZz09IiwibWFjIjoiMWVhY2E3YjI1OTgwZTFhMmE4YWQ5OGEyOTExM2IwOGNmM2IzOGJiMDk3ODExNDZiNTRmMTkwMDIwMDRkMTJlNCJ9; expires=Fri, 17-Jul-2015 16:43:13 GMT; Max-Age=7200; path=/; httponly Content-Encoding: gzip Content-Length: 112 Connection: close Content-Type: text/plain; charset=UTF-8

The StateAPI method=GET response body:

{"data":"2z1a8070a06090on1001211f010110111101211w101^n5femaXcXzFm.6fQ4b46TMbQ1^1^0o00a6002010000a60020100002000"}

0xdeadbeefc0ffee commented 9 years ago

Hi @gatorace. The data in your response does not match the data in your request. We have used your request in testing and have received a different response to yours. Please can you provide us with a Storyline so we can try to reproduce the issue.

hallshouse commented 9 years ago

Hi Chad: Try using this URL to test your SL2 course: http://learning-templates.com/tincan-launcher.html Let me know if this has the same issue because I've tested extensively and have not had a single issue.

Best Regards, Dennis Hall

chadabaker commented 9 years ago

@daniel-abbey Sorry about the mismatch. Was providing representative information rather than a single request / response. Will provide that below. Could I send you an email on Monday with a Storyline and our Learning Locker info for you to test against?

@hallshouse Same issue with this launcher.

Request headers for State API method=GET:

POST /data/xAPI/activities/state?method=GET HTTP/1.1 Host: learninglocker.xxx.com Connection: keep-alive Content-Length: 533 Origin: https://xxx-xxxx.local User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: / Referer: https://xxx-xxxx.local/mock/Disneydemo1200768/story.html?endpoint=https://learninglocker.xxxx.com/data/xAPI/&auth=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activity_id=http://6QXn4ehXBu7_course_id&grouping=http://6QXn4ehXBu7_course_id&actor={%22objectType%22:%22Agent%22,%22name%22:%22First%20Last%22,%22account%22:{%22homePage%22:%22https://xxx.xxxx.com%22,%22name%22:%22custom.tap.1901%22}}&registration=eb168515-e7d1-4a8a-9d93-542ab8312e96 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8,es;q=0.6,fr;q=0.4

Request payload for StateApi method=GET:

Authorization=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activityId=http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid&Content%2DType=application%2Fjson&agent=%7B%22name%22%3A%22First%20Last%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22https%3A%2F%2Fotp%2Dshdr%2Exxxx%2Ecom%22%2C%22name%22%3A%22custom%2Etap%2E1901%22%7D%7D&stateId=resume&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1&registration=eb168515%2De7d1%2D4a8a%2D9d93%2D542ab8312e96

Response headers for StateApi method=GET:

HTTP/1.1 200 OK Date: Fri, 17 Jul 2015 17:15:11 GMT Server: Apache Strict-Transport-Security: max-age=15768000 Updated: 2015-07-17T17:14:56+0000 ETag: "98156818A154F7AF05B2CE3FA5AA15562AEB2771" Cache-Control: private, must-revalidate X-Experience-API-Version: 1.0.1 Access-Control-Allow-Origin: https://xxx-xxxx.local Vary: Origin,Accept-Encoding Set-Cookie: laravel_session=eyJpdiI6InY2N2JPeVRkWkVLY0tkTmg2STdxb2hiTmEyc0lBa01lSk9rTFFObVJ4Yzg9IiwidmFsdWUiOiJzMnJMYXpHXC9mTlY4WktJNTdxT0JSOE15MjZkT0R0VGZMNUVWZFhlQnUra3lsUFFFOG03UitxaU5kejE1Mlc2aERuRDM1dDhUNmVKSUFBdm1mQmwxXC9BPT0iLCJtYWMiOiJlMjZhODFlMmNjZjc3NWZmNjEyY2JmMGI4Mzg4ZDEzOWY0ZTMwYTg0MjFkOGExYmM2OWI2NDNkNzUyMjgwZDU3In0%3D; expires=Fri, 17-Jul-2015 19:15:11 GMT; Max-Age=7200; path=/; httponly Content-Encoding: gzip Content-Length: 109 Connection: close Content-Type: text/plain; charset=UTF-8

Response payload for StateApi method=GET:

{"data":"2v16607080on1001211f010110111101211w101^n5femaXcXzFm.5YFQtL3QwBl1^1^0o00a6002010000a60020100002000"}

hallshouse commented 9 years ago

@gatorace I have SL2 installed and can take a look at it this weekend or Monday. Share it with me and I'll take a look at the publish settings. Best Regards, Dennis Hall

ht2 commented 9 years ago

Hi @gatorace, I believe this is due to the fact that Storyline is sending the original POST request with a Content-Type of "text/plain". Section 7.3 of the xAPI specification describes how JSON based document storage should be sent in (and out again) with a Content-Type of "application/json". Because LL is receiving the incoming state as "text/plain", LL is returning the same Content-Type back.

ht2 commented 9 years ago

Wait, sorry - I see that in the body of your POST there is an appended type of application/json, do you have an example of the headers and body used when actually inserting the state?

chadabaker commented 9 years ago

Request headers for PUT ...

POST /data/xAPI/statements?method=PUT HTTP/1.1 Host: learninglocker.zzzz.com Connection: keep-alive Content-Length: 1313 Origin: https://otp-zzzz.local User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: / Referer: https://otp-zzzz.local/mock/demo1200768/story.html?endpoint=https://learninglocker.zzzz.com/data/xAPI/&auth=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activity_id=http://6QXn4ehXBu7_course_id&grouping=http://6QXn4ehXBu7_course_id&actor={%22objectType%22:%22Agent%22,%22name%22:%22First%20Last%22,%22account%22:{%22homePage%22:%22https://otp-zzzz.zzzz.com%22,%22name%22:%22username.tap.1992%22}}&registration=66f0e40b-1ec4-4e56-9e69-334adfe45c5d Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8,es;q=0.6,fr;q=0.4

Request payload for PUT ...

Authorization=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&content=%7B%22context%22%3A%7B%22registration%22%3A%2266f0e40b%2D1ec4%2D4e56%2D9e69%2D334adfe45c5d%22%2C%22contextActivities%22%3A%7B%22grouping%22%3A%7B%22id%22%3A%22http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid%22%7D%2C%22parent%22%3A%7B%22id%22%3A%22http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid%22%7D%7D%7D%2C%22actor%22%3A%7B%22name%22%3A%22First%20Last%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22https%3A%2F%2Fotp%2Dzzzz%2Ezzzzzz%2Ecom%22%2C%22name%22%3A%22username%2Etap%2E1992%22%7D%7D%2C%22verb%22%3A%7B%22id%22%3A%22http%3A%2F%2Fadlnet%2Egov%2Fexpapi%2Fverbs%2Fexperienced%22%7D%2C%22version%22%3A%221%2E0%2E0%22%2C%22object%22%3A%7B%22id%22%3A%22http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid%2F5p1rdsD4DRB%22%2C%22objectType%22%3A%22Activity%22%2C%22definition%22%3A%7B%22type%22%3A%22http%3A%2F%2Fadlnet%2Egov%2Fexpapi%2Factivities%2Fmodule%22%2C%22name%22%3A%7B%22und%22%3A%222%2E%20%E4%B9%90%E5%9B%AD%E4%BB%8B%E7%BB%8D%22%7D%2C%22description%22%3A%7B%22und%22%3A%222%2E%20%E4%B9%90%E5%9B%AD%E4%BB%8B%E7%BB%8D%22%7D%7D%7D%7D&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1&statementId=550c4f4c%2Dc685%2D42ff%2D89cd%2Dda8b24ad94e1&Content%2DType=application%2Fjson

Response headers for PUT ...

HTTP/1.1 204 No Content Date: Mon, 20 Jul 2015 13:22:45 GMT Server: Apache Strict-Transport-Security: max-age=15768000 Access-Control-Allow-Origin: https://otp-zzzz.local Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization, X-Requested-With, X-Experience-API-Version, X-Experience-API-Consistent-Through, Updated Access-Control-Allow-Credentials: true X-Experience-API-Consistent-Through: 2015-07-20T13:22:45.755200+00:00 X-Experience-API-Version: 1.0.1 Cache-Control: no-cache Vary: Origin,Accept-Encoding Set-Cookie: laravel_session=eyJpdiI6IjdYZElNZnpOckMrNDF4cnBwWVNaZFNBc3JUQnhxcE1oZzVrQlNGdVN6U0U9IiwidmFsdWUiOiJJSVVNMlFcL3dGZFEydTlqWHBnSEpvRXYyZFpuVkZnOFVXUUVXQ0s5cGwxbU5lblFnRVlFWlV5b3RsM3h3cmlsOE51XC96Z21nYkRoaEdpd1NDMzBySXdBPT0iLCJtYWMiOiI5MGRhYTU4NGEzZGY4YWFiYWM2ZDkwOTczODNkMmU3YTczNDZjMGQwNTg3ODE0ZjRmZmYxMmM5MWI2MDMzY2M3In0%3D; expires=Mon, 20-Jul-2015 15:22:45 GMT; Max-Age=7200; path=/; httponly Content-Length: 1 Connection: close Content-Type: text/html; charset=utf-8

chadabaker commented 9 years ago

Sorry ... wrong PUT ... that is for the StatementAPI ... will add the StateAPI PUT below ...

chadabaker commented 9 years ago

Request headers for StateAPI PUT ...

POST /data/xAPI/activities/state?method=PUT HTTP/1.1 Host: learninglocker.zzzz.com Connection: keep-alive Content-Length: 668 Origin: https://otp-zzzz.local User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: / Referer: https://otp-zzzz.local/mock/demo1200768/story.html?endpoint=https://learninglocker.zzzz.com/data/xAPI/&auth=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activity_id=http://6QXn4ehXBu7_course_id&grouping=http://6QXn4ehXBu7_course_id&actor={%22objectType%22:%22Agent%22,%22name%22:%22First%20Last%22,%22account%22:{%22homePage%22:%22https://otp-shdr.zzzz.com%22,%22name%22:%22username.tap.1992%22}}&registration=66f0e40b-1ec4-4e56-9e69-334adfe45c5d Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8,es;q=0.6,fr;q=0.4

Request payload for StateAPI PUT ...

activityId=http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid&Authorization=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1&registration=66f0e40b%2D1ec4%2D4e56%2D9e69%2D334adfe45c5d&agent=%7B%22name%22%3A%22First%20Last%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22https%3A%2F%2Fotp%2Dzzzz%2Ezzzz%2Ecom%22%2C%22name%22%3A%22username%2Etap%2E1992%22%7D%7D&content=%7B%22data%22%3A%222o146070ji1001111a0101101111w101%5En5femaXcXzFm%2E5p1rdsD4DRB1%5E1%5E0o00a6102000000a61020000002000%22%7D&stateId=resume&Content%2DType=application%2Fjson

ht2 commented 9 years ago

OK, looks to me like the Content-Type that is sent as part of the payload is being ignored because a Content-Type is being sent in the headers (in the standard fashion). Storyline is quite awkward in that it will always use the GET and POST verbs (as some browsers do not support Cross Origin Resource Sharing and therefore do not support other HTTP verbs). Instead it sends everything inside the body payload as defined here.

The next step will be to work out why the Content-Type passed in the payload is not being honoured above the header passed in the request.

chadabaker commented 9 years ago

Tried modifying "getPostContent" in "/app/controllers/xapi/DocumentController.php" ...

From: $contentType = \LockerRequest::header('Content-Type');

To: $contentType = \LockerRequest::getParam('Content-Type', \LockerRequest::header('Content-Type'));

Result: Content stored (and subsequently returned) as application/json for the StateAPI request. Unfortunately, the course refuses to offer the resume prompt. I'll revert this code and see if there's a better solution to the content type issue. In the meantime, I'll also need to do some more research as to why the prompt is not working.

chadabaker commented 9 years ago

Further information, now that GET request is returning application/json (based on above code change). I haven't gone through all of this myself as of yet, but I am leaving for the day and thought I'd share.

Captured request/response details for the GET request when launching with Learning Locker and Scorm Cloud. Some obvious differences based on Scorm Cloud platform, but wondering if there's something else in this response that might be the cause.

NOTE: FEEL FREE TO IGNORE THIS INFORMATION ... Just posting ahead of my own review based on possible time zone differences of our efforts. Thanks again for looking into this issue!

LL StateAPI GET request headers

POST /data/xAPI/activities/state?method=GET HTTP/1.1 Host: learninglocker.xxxxxx.com Connection: keep-alive Content-Length: 518 Origin: https://otp-xxxx.local User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: / Referer: https://otp-xxxx.local/mock/companydemo1200768/story.html?endpoint=https://learninglocker.xxxxxx.com/data/xAPI/&auth=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activity_id=http://6QXn4ehXBu7_course_id&grouping=http://6QXn4ehXBu7_course_id&actor={%22objectType%22:%22Agent%22,%22name%22:%22First%20Last%22,%22account%22:{%22homePage%22:%22https://otp-xxxx.xxxxxx.com%22,%22name%22:%22chad%22}}&registration=aabd446f-bba3-4eed-9266-ff105887d571 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8,es;q=0.6,fr;q=0.4

LL StateAPI GET request payload

Authorization=Basic%20ZTM5MWE4OTU1NjM1ZWE4ODk1YjUzNjRiNTE5YjY1YzlmNjZkMWQ5MjplODZjYWI2MzM4NTRmNjRmYWNlNjMyN2YxOGEyMjUxN2FlZDMxOWFk&activityId=http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid&Content%2DType=application%2Fjson&agent=%7B%22name%22%3A%22First%20Last%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22https%3A%2F%2Fotp%2Dxxxx%2Exxxxxx%2Ecom%22%2C%22name%22%3A%22chad%22%7D%7D&stateId=resume&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1&registration=aabd446f%2Dbba3%2D4eed%2D9266%2Dff105887d571

LL StateAPI GET response headers

HTTP/1.1 200 OK Date: Mon, 20 Jul 2015 21:05:48 GMT Server: Apache Strict-Transport-Security: max-age=15768000 Updated: 2015-07-20T21:03:24+0000 ETag: "2185182BC88430A9A257A040DF7C5C9DC2404AFE" Cache-Control: private, must-revalidate X-Experience-API-Version: 1.0.1 Access-Control-Allow-Origin: https://otp-xxxx.local Vary: Origin,Accept-Encoding Set-Cookie: laravel_session=eyJpdiI6IlRcLzdKZzk3UU9kNmd0SG5QN3c5MW1zYVRiN1lRckpcL3RtQ1BiU25Ja3hNYz0iLCJ2YWx1ZSI6IjRKZTNQS1N2cFdGRDU3QzV3V1pXRTB3ZktmUTdUdVdrR1cxVDljTUhWZjF2bzlPbDRuNjNDaXRza0N0dHFHb0NnOW9XSXE1WVdJNHNtZWRDRVo2SHVnPT0iLCJtYWMiOiJhYmFhNTVlNGFkYjU0MjllZWQwNDc4Mjg2OWZhNmE3ZTM3NWFhNDZlY2M5NGQyMzYwZDRiYzk3YTc3ZTJiNDE2In0%3D; expires=Mon, 20-Jul-2015 23:05:48 GMT; Max-Age=7200; path=/; httponly Content-Encoding: gzip Content-Length: 101 Connection: close Content-Type: application/json

LL StateAPI GET response body

{"data":"2o146070ji1001111a0101101111w101^n5femaXcXzFm.5p1rdsD4DRB1^1^0o00a6001020000a60010200002000"}

Scorm Cloud StateAPI GET request headers

POST /tc/A3LT4PWQ65/sandbox/activities/state?method=GET HTTP/1.1 Host: cloud.scorm.com Connection: keep-alive Content-Length: 1616 Origin: https://cloud.scorm.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: / Referer: https://cloud.scorm.com/content/courses/A3LT4PWQ65/companydemo12007683e9ae518-3e72-40ab-aea3-3baf02496954/0/story.html?externalRegistration=PL3EC77RF53VR6WJV4G5WGUCFQORHUFRQ4QCRIMTTOQTXOWS4Z7NKLIITGWKNWZRE55COSQA2KSKAXMD6KM5MFFO77OLPUDJWOKUAZIDWZ2CXFQJBAVTGVBTNGJN4ASA5KGKF46T5H3UQ&grouping=http%3A%2F%2F6QXn4ehXBu7_course_id&activity_id=http%3A%2F%2F6QXn4ehXBu7_course_id&content_endpoint=https%3A%2F%2Fcloud.scorm.com%2Ftc%2FA3LT4PWQ65%2Fsandbox%2Fcontent%2F&actor=%7B%22name%22%3A%5B%22Chad%20Baker%22%5D%2C%22account%22%3A%5B%7B%22accountServiceHomePage%22%3A%22http%3A%2F%2Fcloud.scorm.com%2F%22%2C%22accountName%22%3A%22A3LT4PWQ65%7Cchad.a.baker.-nd%40disney.com%22%7D%5D%2C%22objectType%22%3A%22Agent%22%7D&content_token=3bc66761-65d8-4a5c-a7f9-53fbc9c81c0f&registration=5e03e521-f1db-4839-ba5c-e444eaeb9f94&externalConfiguration=PL3EC77RF53VR6WJV4G5WGUCFSFVOT7RGHXFLTLKASRTXH4FCQ5BDZQNW4TQCWUPXL5LJEU76QO6MNGHM6SHUDU6KFYLNHJK4WBYZNTCAPN5KBDQI4EFGDFDJOV43GH6O2AZBCACMP7ZJJH5HGRMBSQOMQ62RBRXKVAVRAE37EWIONQERHUGC6F2GKOFRLRO3XS3B4QFLL7EWMKMHZOYKSBOUNIFZ265JK2MUTAJ6HYAMZ3JT3HQMBEXDV5I5FL3QWAHFTQKDU5DS2PEUUEM3YVM5SIBLKYR3MY42J64ZR6D7HXFFACJ6LFIF3DSZLMORGVTL4D53ZIA2TPCIJIPZAI7X5ZTEDNNXYQPIEAQPMJS5PMFLMFYHNDDFJIYCVLCFJNSCN6DTI2F2OI5GLKE2U6LFPWGMJ2NWFHARUOYGGHIRAE5DHF4UIFCJQIESGIUPIWXMPQH25IK36UPMVZFBQTXD7LVDNDZRO3VECZIHDRLMGO5ZENKGPEYUPDKMZ4IHEVQ7QEHJOKR54CXYKARKQOEJ4INKK4HJFRW73BASWAMIHELR74W3F5XJWFI6ILNKZ2PH23T6ZJ3NHJ7C3UFV52D2YSMJOKJOEU32DTYHVJAKXFZIBNQPF4GI26FXAIOT7M5H6PPQQIIVOPPR7LFSQHBJQYAKPFQLODWQ2BCHXECQFXJ7KOK36Y6WQAYBKZO2GTIJYUZUGKT467CERQZNAF7YEXVNLZYHR6EPCIMLRRKHNKM2FHPTWJXUZFW2RPXB336LO2KJCW5E2QSYGPJKT7XEU3XWAGRMWJFGZ5SVCH4L4H4HUWGTKPTQHFJ25B6YEO4B6SQW4YIAQAMQ3HEPZGDAJQQ7MDRZXGCLZYI6SGTH3TZFI6A&auth=Basic%20OmQwMjc1MzhlLWUyMDgtNDBmNC05OGEwLTJjNGUxN2I3MzRmZA%3D%3D&endpoint=https%3A%2F%2Fcloud.scorm.com%2Ftc%2FA3LT4PWQ65%2Fsandbox%2F&width=988&height=724&left=466&top=0 Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8,es;q=0.6,fr;q=0.4 Cookie: optimizelyEndUserId=oeu1437147525726r0.8255753242410719; mktoPPCKeyword=; mktoSearchEngine=Google; mktoSearchString=; mktoAdGroup=; mktoCampaign=; utma=176311463.1387519577.1437147527.1437147527.1437147527.1; utmz=176311463.1437147527.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); _mkto_trk=id:319-AOE-283&token:_mch-scorm.com-1437147527155-68114; optimizelySegments=%7B%7D; optimizelyBuckets=%7B%7D; __utmt=1; SC_SESSION=df6b6959-672a-4807-a304-9231c8d4421b; utma=245516374.1860010119.1437147531.1437147531.1437425881.2; utmb=245516374.2.10.1437425881; utmc=245516374; utmz=245516374.1437147531.1.1.utmcsr=scorm.com|utmccn=(referral)|utmcmd=referral|utmcct=/scorm-solved/scorm-cloud-features/

Scorm Cloud StateAPI GET request payload

width=988&height=724&agent=%7B%22name%22%3A%22Chad%20Baker%22%2C%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22http%3A%2F%2Fcloud%2Escorm%2Ecom%2F%22%2C%22name%22%3A%22A3LT4PWQ65%7Cchad%2Ea%2Ebaker%2E%2Dnd%40disney%2Ecom%22%7D%7D&Authorization=Basic%20OmQwMjc1MzhlLWUyMDgtNDBmNC05OGEwLTJjNGUxN2I3MzRmZA%3D%3D&activityId=http%3A%2F%2F6QXn4ehXBu7%5Fcourse%5Fid&X%2DExperience%2DAPI%2DVersion=1%2E0%2E1&registration=5e03e521%2Df1db%2D4839%2Dba5c%2De444eaeb9f94&externalConfiguration=PL3EC77RF53VR6WJV4G5WGUCFSFVOT7RGHXFLTLKASRTXH4FCQ5BDZQNW4TQCWUPXL5LJEU76QO6MNGHM6SHUDU6KFYLNHJK4WBYZNTCAPN5KBDQI4EFGDFDJOV43GH6O2AZBCACMP7ZJJH5HGRMBSQOMQ62RBRXKVAVRAE37EWIONQERHUGC6F2GKOFRLRO3XS3B4QFLL7EWMKMHZOYKSBOUNIFZ265JK2MUTAJ6HYAMZ3JT3HQMBEXDV5I5FL3QWAHFTQKDU5DS2PEUUEM3YVM5SIBLKYR3MY42J64ZR6D7HXFFACJ6LFIF3DSZLMORGVTL4D53ZIA2TPCIJIPZAI7X5ZTEDNNXYQPIEAQPMJS5PMFLMFYHNDDFJIYCVLCFJNSCN6DTI2F2OI5GLKE2U6LFPWGMJ2NWFHARUOYGGHIRAE5DHF4UIFCJQIESGIUPIWXMPQH25IK36UPMVZFBQTXD7LVDNDZRO3VECZIHDRLMGO5ZENKGPEYUPDKMZ4IHEVQ7QEHJOKR54CXYKARKQOEJ4INKK4HJFRW73BASWAMIHELR74W3F5XJWFI6ILNKZ2PH23T6ZJ3NHJ7C3UFV52D2YSMJOKJOEU32DTYHVJAKXFZIBNQPF4GI26FXAIOT7M5H6PPQQIIVOPPR7LFSQHBJQYAKPFQLODWQ2BCHXECQFXJ7KOK36Y6WQAYBKZO2GTIJYUZUGKT467CERQZNAF7YEXVNLZYHR6EPCIMLRRKHNKM2FHPTWJXUZFW2RPXB336LO2KJCW5E2QSYGPJKT7XEU3XWAGRMWJFGZ5SVCH4L4H4HUWGTKPTQHFJ25B6YEO4B6SQW4YIAQAMQ3HEPZGDAJQQ7MDRZXGCLZYI6SGTH3TZFI6A&externalRegistration=PL3EC77RF53VR6WJV4G5WGUCFQORHUFRQ4QCRIMTTOQTXOWS4Z7NKLIITGWKNWZRE55COSQA2KSKAXMD6KM5MFFO77OLPUDJWOKUAZIDWZ2CXFQJBAVTGVBTNGJN4ASA5KGKF46T5H3UQ&Content%2DType=application%2Fjson&stateId=resume&top=0&left=466

Scorm Cloud StateAPI GET response headers

HTTP/1.1 200 OK Access-Control-Allow-Headers: Content-Type,Content-Length,Authorization,If-Match,If-None-Match,X-Experience-API-Version,X-Experience-API-Consistent-Through Access-Control-Allow-Methods: HEAD,GET,POST,PUT,DELETE Access-Control-Allow-Origin: * Access-Control-Expose-Headers: ETag,Last-Modified,Cache-Control,Content-Type,Content-Length,WWW-Authenticate,X-Experience-API-Version,X-Experience-API-Consistent-Through Cache-Control: no-cache Content-Type: application/json Date: Mon, 20 Jul 2015 21:05:34 GMT ETag: "4ECA365F7C8777360E0CA5DD3F0B125C2C7E3430" Last-Modified: Mon, 20 Jul 2015 21:02:10 GMT Server: Apache X-Experience-API-Version: 1.0.1 X-XSS-Protection: 1; mode=block Content-Length: 100 Connection: keep-alive

Scorm Cloud StateAPI GET response body

{"data":"2m1c1070a06090809810012110w101^n5femaXcXzFm.6fQ4b46TMbQ1^1^0o00a6102000000a61020000002000"}

fugu13 commented 9 years ago

Most of that's just stuff SCORM Cloud specific stuff being done because you're launching it out of SCORM Cloud itself. If you launch it from your local machine but with the LRS pointed at SCORM Cloud (or Wax ;) ) you should see much more comparable communication, which'll be easier to sort through for differences.

hallshouse commented 9 years ago

@gatorace I really cannot see LearningLocker as the issue here. I have tested SL2 extensively with LL from 1.4 to current and the only errors I've had were all due to my URL being misconfigured. I'll be happy to work with you to resolve this, but need to know your Tin-Can publish settings to start with. Can you provide the following:

  1. Your LRS xAPI URL
  2. LRS Instance Username and Password
  3. Your agent info for the URL
  4. Your Activity ID information (full path)

I'll create my own SL2 project and launch it then let you know my results. You should also be able to view my statements in the LRS instance afterward.

chadabaker commented 9 years ago

Will need to get confirmation on providing access. In meetings all day today, so it might be tomorrow.

Thanks again for the help ...

andrewhickey commented 9 years ago

Hi @gatorace, you still having problems or did you manage to get things working?

chadabaker commented 9 years ago

Still having issuses.

Things I've done to StateAPI GET response (when course initially loads) ... 1) Changed content-type to application/json 2) Change CORS headers to match those being sent by Scorm Cloud ** 3) Confirmed data in PUT matches data returned by GET 4) Removed gzip compression of response 5) Changed cache-control headers to match those being sent by Scorm Cloud

* Haven't been able to get the Access-Control-Allow-Origin header to change from the "Origin" value to simply "" as it is returned by Scorm Cloud

Trying to do ... 1) Change Access-Control-Allow-Origin header to simply "*" 2) Remove leading space from response body (shouldn't be an issue, JSON specification allows white space characters before and after structure characters) 3) Test against demo LL ... worked! ... See that the leading space is gone from response body and access-control-allow-origin is my local domain.

Not sure where that leading space is coming from in my response ... I'm going to hunt this down to see if that's the issue.

chadabaker commented 9 years ago

That was it ... found a leading white space (" <?php") in our database configuration file (that developer is getting punked on Monday). Removed and now the resume works.

Thanks again for the help. Sorry for the wild goose chase. Will have to submit a bug with Articulate that their JSON support needs to be improved.

Let me know if you'd like any more details.

fugu13 commented 9 years ago

Oh, PHP...

But what makes this really weird is, leading whitespace is totally legal JSON and doesn't change the meaning. That means whatever code is being used in Storyline is doing things in bad ways.

edit: not your code, Storyline's internal code

chadabaker commented 9 years ago

No doubt ... have submitted the bug to Articulate to prevent others from chasing down ghosts.

Thanks again to all ... closing the issue.

12amCoder commented 8 years ago

Hi Guys,

I am facing the same issue which just the course doesn't prompt for resume.

Version 1.13.3 (from VERSION file)

Steps to reproduce the bug

  1. Create working launch link to course
  2. Launch course and play through a bit
  3. Close course
  4. Re-launch course with same activity, actor, and registration
  5. See that course does not prompt for resume

Expected behaviour

  1. Course should prompt for resume

Actual behaviour As noted above, course does not prompt for resume

Server information Local WAMP Server with MongoDb

Client information OS: Window 10 64 bit Browser: Version 51.0.2704.106 m (64-bit)

Additional information Tested the same course with ScormCloud and it is working fine. But couldn't get it work with LearningLocker.

The difference I notice is it return {} instead of { data:"xxxx" } in the http://localhost:8081/learninglocker/public/data/xAPI/activities/state?method=GET

I am not sure if the parameter I pass to the server is correct or not. ?endpoint=http://localhost:8081/learninglocker/public/data/xAPI/&auth=Basic%20M2FjNDAwNWZhNDY4YWQ4M2Y2ZjUxMTZjN2UwMDdmMDIyMjJhZjdkNzozOTE1MzI5ODcxN2QxYjFmZTI3MzY5OGI2NWJjNzBjNzdlODUwNTFj&actor={"mbox":"mailto:xxx@xxx.com",%20"name":"Jason"}&registration=2981c910-6445-11e4-9803-0800200c9a66&activity_id=www.example.com/my-activity

Also I am not sure where to get/generate for the registration and activity_id paramenter for, I just copy from the tutorial website and use it. Is that the reason it doesn't work?

12amCoder commented 8 years ago

I notice in documentapi table, there is 1 record doesn't have registration (null) and content (null). Does it related to the reason why it returns {} instead of {data:'...'}?

Other fields got value

{
    "_id" : ObjectId("57991e7d7f7759ac2600002c"),
    "lrs" : ObjectId("57991beb7f7759b02100002d"),
    "lrs_id" : ObjectId("57991beb7f7759b02100002d"),
    "documentType" : "state",
    "identId" : "resume",
    "activityId" : "http://5a8SiBHMf0l_course_id",
    "agent" : {
        "mbox" : "mailto:xxx@xxx.com",
        "name" : "Jason"
    },
    "registration" : null,
    "updated_at" : ISODate("2016-07-27T21:31:27.000Z"),
    "sha" : "AA7B6DA600F7E471DEEE83DCB06F923C6353FF65",
    "content" : null,
    "contentType" : "application/json",
    "created_at" : ISODate("2016-07-27T20:50:05.000Z")
}
ryasmi commented 8 years ago

@Js-uniqsign it seems that this was an issue with Storyline not Learning Locker, is that what you're using?

Which tutorial are you using?