Connecting moodle api through web service - javascript

Let me explain: My purpose is to create moodle users from a web app.
I am implementing a web app on Tomcat 8.0.15.0. That is, I use java servlets on the server side. Many JSP files and javascript, with much of it in jQuery, resides on the client side.
On the other hand, on another server, I have a test moodle installation. Via site-administration> plugins> web services> external services, I created a ws that enables the core_user_create_users function. Also created a token to access this ws, and put the admin user as authorized user.
And then, typed the following URL on Chrome:
https://mysyte.com/webservice/rest/server.php?wstoken=780f8b3a1164163d4dc00a757071194e&wsfunction=core_user_create_users&moodlewsrestformat=json&users[0][username]=testuser&usr[ [email] =john#smith.com&users [0] [password] = XXXXXX
And it worked. It returned a blank page, with the text
[{"id": 1, "username": "testuser"}]
Thus creating a user in moodle.
My question is: How can I do this from java?, or from javascript?, or from jQuery even better.
And if not, from PHP, I guess I would have no problem calling it from java, or javascript, or jQuery.
My Wrong Hint: In another part of the application I used, in javascript, the call $.getJSON() successfully. That's why I thought would also serve me in this case. But no success now, when the mozilla debugger reaches the call, it hangs.
Any feedback will be most welcome.
The call looks like
function create_moodle_user(username,firstname,lastname,email,password) {
var url = "https://mysyte.com/webservice/rest/server.php?"
+ "wstoken=780f8b3a1164163d4dc00a757071194e" + "&"
+ "wsfunction=core_user_create_users" + "&"
+ "moodlewsrestformat=json" + "&"
+ "users[0][username]=" + username + "&"
+ "users[0][firstname]=" + firstname + "&"
+ "users[0][lastname]=" + lastname + "&"
+ "users[0][email]=" + email + "&"
+ "users[0][password]=" + password;
$.getJSON(url, function(data) { // should return [{"id":4,"username":"testuser"}]
// this point is never reached
if (data.length < 64) {
}
else {
}
});
}

Finally, it worked by changing the call and the way how parameters were passed.
function create_moodle_user(u,f,l,e,fn) {
var domainname = 'https://my.moodle.site.com';
var data = {
wstoken: '780f8b3a1164163d4dc00a757071194e'
wsfunction: 'core_user_create_users'
moodlewsrestformat: 'json',
users: [
{
username:u,
password:'xxxxxxxx',
email:e,
firstname:f,
lastname:l
}
]
};
var response = $.ajax({
type: 'GET',
data: data,
url: domainname + '/webservice/rest/server.php'
});
// pass the function parameter
response.done(fn);
}
And this worked!
My problem now is to get user info, since I don't know how to get the response from core_user_get_users_by_field.
This is what I have:
function get_moodle_user(u,fn) {
var domainname = 'https://my.moodle.site.com';
var data = {
wstoken: '780f8b3a1164163d4dc00a757071194e'
wsfunction: 'core_user_get_users_by_field'
moodlewsrestformat: 'json',
field: 'username',
username:u
};
var response = $.ajax({
type: 'GET',
data: data,
url: domainname + '/webservice/rest/server.php'
});
console.log(response); // this does not show the result data
// pass the function parameter
response.done(fn);
}
Any ideas, please?

Related

Can jQuery/Javascript/Ajax manage its own session cookies separate from browser cookies?

I have a strange project where I need to embed some json data into a sharepoint page, and the requirements given to me mean it has to be done in an embedded javascript web snippet. This data will be coming from a rest API which requires authentication. I'm moderately familiar with this level of web programming, but most of my experience is not this deep with things like CORS and strange session work.
Locally, I do this in 2 steps. I can make an authentication request (a POST request with action "login" and a username and password) which then gives my browser a session cookie, then I can do a second request with an action "getData" and everything works.
In the javascript, I am able to successfully login, but the session information does not persist to subsequent requests. I'm not sure how to handle this, or if it's even possible. I've played around with lots of code and tried using a jQuery Cookie plugin, but nothing seems to work. I am open to any suggestions on a better way to solve this problem, or if there's a technical reason this will never work I need to know that. Here's some prototype code:
var payload = { action : 'login' , username : 'username', password : 'password' }
$.ajax({
type: "POST",
url: 'https://fqdn/api',
data: payload ,
crossDomain: true,
async: true,
success: function (r, status, xhr ){
var xml_serializer = new XMLSerializer();
$('#DebugDiv1').text("test.Post.Success\n" + r + "\n" + xml_serializer.serializeToString(r) );
var params = {'action':'getData'}
$.ajax({
type: "GET",
url: "https://fqdn/api",
dataType: 'json',
data: params,
crossDomain: true,
async: true,
success: function ( s, status, xhr ){
var xml_serializer = new XMLSerializer();
$('#DebugDiv3').html(s);
$('#DebugDiv4').text("test.Post.Success\n" + r + "\n" + xml_serializer.serializeToString(s) );
},
error: function (s, status, xhr ){
$('#DebugDiv3').text("test.Get.Error \n readyState: " + .readyState + "\nstatus: " + s.status + "\nstatusText: " + s.statusText );
$('#DebugDiv4').text(s.responseText);
}
});
},
error: function (r, status, xhr ){
$('#DebugDiv1').text("test.Post.Error \n readyState: " + r.readyState + "\nstatus: " + r.status + "\nstatusText: " + r.statusText );
$('#DebugDiv2').text(JSON.stringify(r));
}
});

Cordova app has internet connection via emulator, but not on device [update: ajax problem]

I am trying to build a small app via cordova that sends data to a PERL-Script on a server. The debug and release build work fine on the genymotion emulator, however sending the data from Android phones does not work. There is no error message from the app (either, which is supposed to show up when the connection fails).
Running USB debugging, I do get the follwoing invoke error message (the savedataLastpage funtion is supposed to send the data):
Uncaught TypeError: Illegal invocation
at e (jquery-2.1.3.min.js:4)
at Ac (jquery-2.1.3.min.js:4)
at Function.n.param (jquery-2.1.3.min.js:4)
at Function.ajax (jquery-2.1.3.min.js:4)
at Object.saveDataLastPage (index.js:631)
at Object.renderLastPage (index.js:461)
at Object.recordResponse (index.js:597)
at HTMLButtonElement.<anonymous> (index.js:357)
at HTMLButtonElement.dispatch (jquery-2.1.3.min.js:3)
at HTMLButtonElement.r.handle (jquery-2.1.3.min.js:3)
The pertaining code is the following:
index.js:631
saveDataLastPage:function() {
$.ajax({
type: 'post',
url: '/URL/',
data: localStore,
crossDomain: true,
success: function (result) {
var pid = localStore.participant_id, snoozed = localStore.snoozed, uniqueKey = localStore.uniqueKey, pause_time=localStore.pause_time;
localStore.clear();
localStore.participant_id = pid;
localStore.snoozed = snoozed;
localStore.uniqueKey = uniqueKey;
localStore.pause_time=pause_time;
$("#question").html("<h3>Thank you, your responses have been sent.</h3>");
},
error: function (request, error) {
console.log(error);
$("#question").html("<h3>Error: Please check your internet connection.</h3><br><button>Send again</button>");
$("#question button").click(function () {app.saveDataLastPage();});
}
});
},
index.js:461
else {
var datestamp = new Date();
var year = datestamp.getFullYear(), month = datestamp.getMonth(), day=datestamp.getDate(), hours=datestamp.getHours(), minutes=datestamp.getMinutes(), seconds=datestamp.getSeconds(), milliseconds=datestamp.getMilliseconds();
localStore[uniqueKey + '.' + "completed" + "_" + "completedSurvey" + "_" + year + "_" + month + "_" + day + "_" + hours + "_" + minutes + "_" + seconds + "_" + milliseconds] = 1;
app.saveDataLastPage();
}
As stated before, on the genymotion emulator the ajax script works fine without the error and sends the data to the script.
I'm not sure why the emulator would work just fine but the error Uncaught TypeError: Illegal invocation suggests that it is a problem with the ajax post call. Specifically, the default setting of processing the data into a query string likely fails.
From the ajax documentation:
By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option to false.
That means you can either turn off the processing processData: false which will post the data in the body of the request or you have to transform the localStore data into a proper object (from whatever it was before).
If it is like an object you can do the following:
var data = {};
for (var elem in localStore) {
data[elem] = localStore[elem];
}
or possibly in brief:
var data = {};
localStore.each(function(elem) { data[elem.name] = elem.value; });

Google Classroom API 401 Error

I am trying to create a Google Classroom course using the Google Classroom API and a service account. I am currently experimenting using JavaScript and I have everything set up and working to get a list of course. I set up a JWT and request an authentication token which I receive.
{"access_token":"----ACCESS TOKEN HERE----------","token_type":"Bearer","expires_in":3600}
When I use this to retrieve a user's course list (via GET) there is no problem. I receive back a proper response with a list of courses which I then display in a table.
When I try to use the same process to try to create a course (via POST), I get a 401 error:
{
"error": {
"code": 401,
"message": "The request does not have valid authentication credentials.",
"status": "UNAUTHENTICATED"
}
}
This is the code I use to authenticate:
function authenticate(callback) {
function b64EncodeUnicode(str) {
str = JSON.stringify(str);
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
// constuct the JWT
var jwtHeader = {
"alg":"RS256",
"typ":"JWT"
}
jwtHeader = JSON.stringify(jwtHeader);
//construct the Claim
var jwtClaim = {
"iss":"psclassroomsync#psclassroomsync.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom.rosters",
"sub":"myemail#address.com", //this is an admin account I shouldn't really need this but tried with and without it
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp":(Math.round(new Date().getTime()/1000) + 60 * 10),
"iat":Math.round(new Date().getTime()/1000)
}
jwtClaim = JSON.stringify(jwtClaim);
//construct the signature
var key="-----BEGIN PRIVATE KEY-----Removed-----END PRIVATE KEY-----\n";
var jwtSign = b64EncodeUnicode(jwtSign);
var sJWT = KJUR.jws.JWS.sign("RS256", jwtHeader, jwtClaim, key);
var jwt = jwtHeader + "." + jwtClaim + "." + sJWT;
//request Token
var grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";
var tokenRequest = "grant_type=" + grantType + "&assertion=" + sJWT;
var postURL = "https://www.googleapis.com/oauth2/v4/token"
request = $j.ajax({
url: postURL,
type: "post",
data: tokenRequest,
success: callback
});
}
This is the code I use to GET the course list. (this works)
$j("#getClasses").click(function(event){
function getClasses(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'teacherId=~(teacheremail)&access_token='+access_token;
var files = $j.ajax({
url: apiUrl,
type: "get",
data: myData,
success: function (data) {
var retreivedClasses = JSON.stringify(data);
for(var i = 0; i < data['courses'].length; i++){
nextObject = data['courses'];
$j('#classListTable').append('<tr><td>' + nextObject[i]['name'] + '</td><td>' + nextObject[i]['courseState'] + '</td><td>' + nextObject[i]['enrollmentCode'] + '</td></tr>');
}
//$j('#classList').text(retreivedClasses);
}
});
});
}
getClasses();
});
This is the code that I use to create a course via POST. I've hard coded a few of the variables for testing but still gives the 401 error.
$j("#createClass").click(function(event){
function createClass(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var tokenInfo = $j.ajax({
url: 'https://www.googleapis.com/oauth2/v3/tokeninfo',
type: 'get',
data: "access_token="+access_token
});
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'access_token='+access_token + '&ownerId=myemail#address.com&name=myClass'
console.log(myData);
var newGoogleClassroom = $j.ajax({
url: apiUrl,
type: "post",
data: myData,
success: function (data) {
var apiResponse = JSON.stringify(data);
$j('#classCreated').text(apiResponse);
}
});
});
};
createClass();
});
Finally, this is what I get when I get the token info. It looks fine to me i.e. proper scopes: (but I am new at this)
{
"azp": "removed",
"aud": "removed",
"scope": "https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom
.rosters",
"exp": "1474512198",
"expires_in": "3600",
"access_type": "offline"
}
I'd be grateful for any help.
Doug
P.S. I get the security implications of this code. It is in a secure environment for experimentation only. It won't see the light of day.
Based from this forum which is also receiving a 401 error, try to revoke the old oauth. As stated in this related thread, the 401 Unauthorized error you experienced may be related to OAuth 2.0 Authorization using the OAuth 2.0 client ID.
Suggested action: Refresh the access token using the long-lived refresh token. If this fails, direct through the OAuth flow.

Data isn't passed to api call

I'm working on one project with AngularJs(1.5) and Codeigniter rest server. I'm wondering why data idTag isn't passed to php? Let me show you my code and explain further with comments.
I have this factory
factory.get = function(idLocation, idTag){
console.log(idLocation, idTag); //Console log outputs 1 6, so data is here
return $http({
method: 'GET',
url: $location.protocol() + '://' + $location.host() + '/rest/api/locationtag/locationtag/' + idLocation,
data: {
idTag: idTag
}
}).then(function successCallback(response){
console.log(response);
// response is empty, because data isn't sent to PHP
return response.data;
},function errorCallback(response){
console.log('Error getting slide shows: ' + response.data.message);
});
};
And this is my PHP where i try to fetch the code
public function locationtag_get($idLocation)
{
$condition['id_location'] = $idLocation;
$condition['id_tag'] = $this->get('idTag');
var_dump($condition);
die();
$locationTag = $this->locations_tags->get($condition);
if ($locationTag) {
$this->response($locationTag, REST_Controller::HTTP_OK);
}
}
Out put of var_dump is
'id_location' '1'
'id_tag' null
SO the question, why or how to properly send data from GET method to PHP rest controller in Codeigniter?
If you need any additional information's, please let me know and i will provide. Thank you in advance!
For GET requests you should use params instead of data (which is for POST requests). You can confirm this in the AngularJS documentation.
params – {Object.} – Map of strings or objects which
will be serialized with the paramSerializer and appended as GET
parameters.
Of course, nothing stops you from adding them to the URL but you'd have to deal with encoding the information properly instead of just passing the JSON object.
You should be using a params property in your $http config object:
$http({
url: $location.protocol() + '://' + $location.host() + '/rest/api/locationtag/locationtag/' + idLocation,
data: {,
method: "GET",
params: {idTag: idTag}
});
This will append as query string to you url, which you can then inspect in your server side code.

Prototype to jQuery Conversion Confusion

I have the following function:
function updateproductselectionxxx(form, productassignment, mainproductid, subprodqty) {
var checkingurl = "shopajaxproductselection.asp";
var pars = 'productassignment=' + productassignment + '&qty=' + subprodqty + '&mainid=' + mainproductid;
var url = checkingurl + '?' + pars;
var target = 'productselectionresult' + productassignment;
var myAjax = new Ajax.Updater(target, checkingurl, {
method: 'post',
parameters: pars
});
}
And I am currently in the process of converting all the javascript on this website to jQuery. Usually I can use something similar to:
function updateproductselection(form, productassignment, mainproductid, subprodqty) {
$.ajax({
type: 'POST',
url: 'shopajaxproductselection.asp',
data: $(form).serialize(),
success: function (response) {
$(form).find('productselectionresult' + productassignment).html(response);
}
});
return false;
}
And that does the trick, however I really only want to send over 1 field as indicated in the first function and I would also like to send along the information I am sending directly to the function upon it being called. JavaScript is definitely not my area of expertise but usually I can muddle through, but this time everything I have tried has caused errors and I'm not getting very far. Any help would be greatly appreciated.
Looks like a bit of confusion between POST and GET. Although the request method is set to POST in the older Prototype version the params are being sent via CGI which normally appear on the server as a GET. It's a bit hard to say more without seeing the server-side code, but you could try this, such that the jQuery version more closely mimics the old Prototype version:
function updateproductselection(form, productassignment, mainproductid, subprodqty) {
var checkingurl = "shopajaxproductselection.asp";
var pars = 'productassignment=' + productassignment + '&qty=' + subprodqty + '&mainid=' + mainproductid;
var url = checkingurl + '?' + pars;
$.ajax({
type: 'POST',
url: url,
data: {},
success: function (response) {
$(form).find('#productselectionresult' + productassignment).html(response);
}
});
return false;
}
Note that I have added a hash # to the start of productselectionresult - this is crucial due to the difference in the way PrototypeJS works. In Prototype, you can use an ID selector like:
$('id')
whereas in jQuery it has to be:
$('#id')

Categories