Template Toolkit + UAPI execute(). How load the data?
Hi
I'm having a hard time manipulating data returned by execute (priv escalation). Here's the call:
Here's the data I'm getting:
I'd like to be able to access the fields by name like hash and calls. This is what I've done so far in my .tt file:
Unfortunately the data is loaded as text not as json. I'm unable to iterate over js. It's just one blob of text. Eventually I'd like to be able to access the fields like this:
Can someone help? Thanks!
result_set = execute("MyPlugin", "GetData", {"user" => CPANEL.user, "uapi_paginate_size" =>CPANEL.CPVAR.item("itemsperpage" ).html, "uapi_paginate" =>"1", "regex" =>(RAW_FORM.item("searchregex" )), "uapi_paginate_start" =>(FORM.item("uapi_paginate_start" ))}Here's the data I'm getting:
Dumper.dump(result_set):
$VAR1 = '[{u\'hash\': u\'904D3DF0\', u\'calls\': u\'2\'}, {u\'hash\': u\'226CD90D\', u\'calls\': u\'1\'}, {u\'hash\': u\'ABA5B8C6\', u\'calls\': u\'2\'}] ';I'd like to be able to access the fields by name like hash and calls. This is what I've done so far in my .tt file:
USE JSON;
js = JSON.parse(JSON.stringify(result_set));Unfortunately the data is loaded as text not as json. I'm unable to iterate over js. It's just one blob of text. Eventually I'd like to be able to access the fields like this:
FOREACH j IN js;
j.calls;
END;Can someone help? Thanks!
-
Hello, I've asked one of our product owners to take a look into this for you as it's a bit more involved than I am able to address. In the meantime if you haven't already you might also take a look at: Template::Manual 0 -
Thank you Lauren. Yes I've definitely browsed over the docs and tried various things. I used the TT vmethods split and match hoping to "extract" the individual items in a list. .split can only split on one character instead of at least two (like .split('},'). Even then it's hackish. I'd still need to break down and import the data between the curly brackets. So more splitting and hacking at the text, which I'm hoping to avoid. What I'm going to try next is to send the data over with "=>" instead of ":" hoping the perlish code of the template can process it better. I'll attempt that tonight and let you know. Thanks 0 -
Looks like the issue was the JSON coming from my priv code. JSON parsed it OK in the template but as a JSON value not an object. So I'm having to do recursive JSON parsing for each line. I'm hoping this won't have a performance impact. {"entries": [{u\'hash\': u\'904D3DF0\', u\'calls\': u\'2\'}, {u\'hash\': u\'226CD90D\', u\'calls\': u\'1\'}, {u\'hash\': u\'ABA5B8C6\', u\'calls\': u\'2\'}];}
[% js = JSON.parse(uapi_result_set.data); FOREACH entry IN js.entries.list; localjs = JSON.parse(entry); Dumper.dump(localjs.calls); Dumper.dump(localjs.hash); END; %]
I'm expecting a few hundred entries on average. Is there a more efficient way of doing this? Thanks!0 -
Can you provide an example of what you are doing in the MyPlugin::GetData function? I think maybe there is a problem with how you are constructing the data on the backend. Without seeing some of what you are doing in the MyPlugin, its a little hard to tell whats going on here. 0 -
Here is an example of writing an API call similar to what you are doing: [CODE=perl]package Cpanel::API::MyPlugin; use strict; use warnings; sub GetData { my ( $args, $result ) = @_; # This is just fake data in the basic layout I think I see in your example output. my $data = [ { hash => { a => 1, b => 2, }, calls => 2, }, { hash => { a => 2, b => 2, }, calls => 1, }, ]; # Set the data you want to return using result->data() method $result->data($data); return 1; } 1;
Then in template toolkit you would do the following:USE Dumper; SET result = execute( "MyPlugin", "GetData", { "user" => CPANEL.user, "uapi_paginate_size" => CPANEL.CPVAR.item("itemsperpage" ).html, "uapi_paginate" =>"1" , "regex" => (RAW_FORM.item("searchregex" )), "uapi_paginate_start" => (FORM.item("uapi_paginate_start" )) } ); IF result.status; FOREACH entry IN result.data; Dumper.dump(entry.calls); Dumper.dump(entry.hash); END; ELSE; # Error reporting result.error.0; END;
A few notes: * When using execute from Template Toolkit, the data is still a perl hashref, arrayref, or scalar depending on what you returned in $result->data() method. * We only encode the data as JSON if you call the API via the remote url syntax. This looks something like:https://hostname.example.com:2083/cpsess##########/execute/MyPlugin/GetData?user=...&uapi_paginate_size=...&...0 -
Let me know if these examples get you past your problem. 0 -
Here is an example of writing an API call similar to what you are doing: [CODE=perl]package Cpanel::API::MyPlugin; use strict; use warnings; sub GetData { my ( $args, $result ) = @_; # This is just fake data in the basic layout I think I see in your example output. my $data = [ { hash => { a => 1, b => 2, }, calls => 2, }, { hash => { a => 2, b => 2, }, calls => 1, }, ]; # Set the data you want to return using result->data() method $result->data($data); return 1; } 1;
Thanks Tom. In my GetData function up above I'm doing an AdminBin function call (priv escalation). In the AdminBin function I'm calling a custom python script (reason why I'm leveraging privilege escalation). Hence the need to jsonify the data returned by the python script for consumption upstream by AdminBin and then cPanel API. This is exactly what my python script returns (simplified but same format):{"entries": [{u\'hash\': u\'904D3DF0\', u\'calls\': u\'2\'}, {u\'hash\': u\'226CD90D\', u\'calls\': u\'1\'}, {u\'hash\': u\'ABA5B8C6\', u\'calls\': u\'2\'}];}
Hmm I'm now able to import the JSON object once and for all and access all its elements by key. I think extra quotes around each element of the list made JSON think those were scalars/values (above json dump is clean and proper). It looks like I'm good to go! Thanks for your help and thanks for the tip re: $Cpanel global variable. Read about it in the docs and was in my todo list. Cheers!0
Please sign in to leave a comment.
Comments
8 comments