AICC PutParam Implementation Questions

Re: AICC PutParam Implementation Questions

by Jack Hsu -
Number of replies: 6

Hi Matteo,

Thank you again for your help.

I packaged an AICC course and named it as Envision_Test_50

After the course was launched, here is the output of the report:

Moodle Report

After clicking on Attempt:

Attempt2

After clicking on Track details:

Attempt1

When I tried to start the course again:

summary1

It seemed like after the course was started, even though the sequence of command I put was : GetParam -> PutParam -> GetParam -> ExitAU, the course was not updated as completed, thus attempt always stays at 1

This is the Grades panel:

Moodle Grades2

Envision_Test_50 is at the very last

In reply to Jack Hsu

Re: AICC PutParam Implementation Questions

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Jack,
I didn't have the time to deepen yet.

BTW, have you already try to use aicc_data and not AICC_data? Could you post the URL of your 4 calls? Spare time permited, I want to start testing on my dev env.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: AICC PutParam Implementation Questions

by Jack Hsu -

Hi Matteo,

Thank you for your response. I finally figured out what was going on. First of all, yes, I used aicc_data. I traced the code in aicc.php and found out that if I use the AICC package created from Articulate Storyline, urlencoded aicc_data could be decoded correctly. Therefore, scores could be updated correspondingly. However, when I used  a skinny package and directed file_name to my Web Application, the urlencoded aicc_data sent by HttpClient in C# could not be decoded correctly when it was passed to aicc.php. So for me, a quick fix is to add a line to decode my aicc_data in aicc.php so that putparam can correctly process it. At this point, I am still not sure why the aicc_data could not be decoded correctly. What do you think?


Cheers!

Jack

In reply to Jack Hsu

Re: AICC PutParam Implementation Questions

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Jack,
that doesn't make sense: you should not alter the Moodle code to add an extra "decode", it could alter your "AICC data" in case of "escaped data" coming legally from other AICC packages.

Could you share both URLs, Storyline and your C# HttpClient, and the C# snippet of your client sending the params, from the new instance of HttpClient() to the response (including the version of the .Net Framework you're compiling with)?
I'm seeing even ":" not being encoded as "%3A" (not really an issue)...

TIA,
Matteo

In reply to Matteo Scaramuccia

Re: AICC PutParam Implementation Questions

by Jack Hsu -
Hi Matteo,


Sorry for the late reply. I was doing some further testing. 

For URLs 

This is what I got from Moodle: 

?aicc_sid=zJLkaTWXpfOPN65BQy44&aicc_url=http://127.0.0.1:3010/mod/scorm/aicc.php&LEARNING_APP_TYPE=LEARNING&WINDOW_STYLE=OWN_WINDOW

This is what I sent to Moodle

%5BCore%5D%0D%0ALesson_Location%3D%0D%0ALesson_Status%3DC%0D%0AScore%3D100%0D%0ATime%3D0000%3A00%3A50%0D%0A%5BComments%5D%0D%0A%0D%0A%5BObjectives_Status%5D%0D%0A%0D%0A%5BStudent_Preferences%5D%0D%0AAudio%3D0%0D%0ALanguage%3D%0D%0ASpeed%3D100%0D%0AText%3D0%0D%0A%5BCore_Lesson%5D%0D%0A2p36607080on1001211f010110111101211w101%5En6cwRYys1ziX.6XR74bD0ClH1%5E1%5E0%7E2f2q039Cag34003400340034000000%7E2K1ed101002g12g1123u_0Q3400340034009490o0s1g09490o000e0f79030o0K0f0111%5E3400yw2Lhq340034003400340097w020111%5E000000002100

The following is my sample code:

        public void Post(String req)

        {

            String message = req.ToString();

            Int32 I_AICC_SID = message.IndexOf("aicc_sid");

            Int32 I_AICC_URL = message.IndexOf("aicc_url");

            Int32 N_AICC_SID_LEN = message.IndexOf('&', I_AICC_SID) - I_AICC_SID - 9;

            Int32 N_AICC_URL_LEN = message.IndexOf('&', I_AICC_URL) - I_AICC_URL - 9;

            String AICC_SID = message.Substring(I_AICC_SID + 9, N_AICC_SID_LEN);

            String AICC_URL = message.Substring(I_AICC_URL + 9, N_AICC_URL_LEN);


            // Setup GetParam

            var client = new HttpClient();

            var values = new Dictionary<string, string>

            {

                { "command", "getparam" },

                { "version", "3.5" },

                { "session_id", AICC_SID }

            };


            var content = new FormUrlEncodedContent(values);


            var response = client.PostAsync(AICC_URL, content).Result;


            var responseString = response.Content.ReadAsStringAsync().Result;


            // Setup PutParam

            var PutParam_values = new Dictionary<string, string>

            {

                { "command", "putparam" },

                { "version", "3.5" },

                { "session_id", AICC_SID },

                { "aicc_data", "%5BCore%5D%0D%0ALesson_Location%3D%0D%0ALesson_Status%3DC%0D%0AScore%3D100%0D%0ATime%3D0000%3A00%3A50%0D%0A%5BComments%5D%0D%0A%0D%0A%5BObjectives_Status%5D%0D%0A%0D%0A%5BStudent_Preferences%5D%0D%0AAudio%3D0%0D%0ALanguage%3D%0D%0ASpeed%3D100%0D%0AText%3D0%0D%0A%5BCore_Lesson%5D%0D%0A2p36607080on1001211f010110111101211w101%5En6cwRYys1ziX.6XR74bD0ClH1%5E1%5E0%7E2f2q039Cag34003400340034000000%7E2K1ed101002g12g1123u_0Q3400340034009490o0s1g09490o000e0f79030o0K0f0111%5E3400yw2Lhq340034003400340097w020111%5E000000002100"}

 

            };


            var PutParam_content = new FormUrlEncodedContent(PutParam_values);


            var PutParam_response = client.PostAsync(AICC_URL, PutParam_content).Result;


            var PutParam_responseString = PutParam_response.Content.ReadAsStringAsync().Result;


            // Setup ExitAU

            var ExitAU_values = new Dictionary<string, string>

            {

                { "command", "exitau" },

                { "version", "3.5" },

                { "session_id", AICC_SID },

            };


            var ExitAU_content = new FormUrlEncodedContent(ExitAU_values);


            var ExitAU_response = client.PostAsync(AICC_URL, ExitAU_content).Result;


            var ExitAU_responseString = ExitAU_response.Content.ReadAsStringAsync().Result;


        }

I agree that I should not add extra "decode"  in the source code, but that was the only way I could make it work. Am I missing some steps?


Thanks!

Jack

In reply to Jack Hsu

Re: AICC PutParam Implementation Questions

by Matteo Scaramuccia -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

Hi Jack,
now I understand the reason why you need to decode at the PHP side:

            // Setup PutParam
            var PutParam_values = new Dictionary<string, string>
            {
                { "command", "putparam" },
                { "version", "3.5" },
                { "session_id", AICC_SID },
                { "aicc_data", "%5BCore%5D%0D%0ALesson_Location%3D%0D%0ALesson_Status%3DC%0D%0AScore%3D100%0D%0ATime%3D0000%3A00%3A50%0D%0A%5BComments%5D%0D%0A%0D%0A%5BObjectives_Status%5D%0D%0A%0D%0A%5BStudent_Preferences%5D%0D%0AAudio%3D0%0D%0ALanguage%3D%0D%0ASpeed%3D100%0D%0AText%3D0%0D%0A%5BCore_Lesson%5D%0D%0A2p36607080on1001211f010110111101211w101%5En6cwRYys1ziX.6XR74bD0ClH1%5E1%5E0%7E2f2q039Cag34003400340034000000%7E2K1ed101002g12g1123u_0Q3400340034009490o0s1g09490o000e0f79030o0K0f0111%5E3400yw2Lhq340034003400340097w020111%5E000000002100"}
            };

var PutParam_content = new FormUrlEncodedContent(PutParam_values)

You code is responsible of that double encoding since FormUrlEncodedContent already encoded using the application/x-www-form-urlencoded MIME type.

Try to set aicc_data as a plain INI file string, using CRLF for EOL, and you'll be done, hopefully.

HTH,
Matteo

In reply to Matteo Scaramuccia

Re: AICC PutParam Implementation Questions

by Jack Hsu -

Hi Matteo,


Thank you for your response. Can't believe I made this mistake. I tried to set aicc_data as a plain string with CRLF. It works perfectly fine now. Thanks again for your help!


Jack