I am attemting to add an item to a sharepoint list from an Apache Cordova application. It first prompts the user to login then it will make a HTTP Post to so the data entry.
I have the following code:
function saveToSharepoint(data) {
var authority = "https://login.microsoftonline.com/common/";
var authContext = new Microsoft.ADAL.AuthenticationContext(authority);
var authResult = authContext.acquireTokenAsync("https://my.sharepoint.com", "4be098f8-2184-4831-9ef7-3d17dbbef6a0", "http://localhost:4400/services/office365/redirectTarget.html")
.then(FormatAndUpload(authResult, data), errorCallback);
}
function FormatAndUpload(authResponse, data) {
var token = authResponse.accessToken;
var expiry = authResponse.expiresOn;
console.log("Token acquired: " + authResponse.accessToken);
console.log("Token will expire on: " + authResponse.expiresOn);
$.ajax({
url: "https://my.sharepoint.com/_api/web/lists/getbytitle('" + Test + "')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify(data),
headers: {
"Accept": "application/json;odata=verbose",
"Authoriztion":"Bearer " + token
},
success: function (data) {
success(data);
},
error: function (data) {
failure(data);
}
});
}
The problem I am having is that the FormatAndUpload method is being called before acquireTokenAsync has completed, so the authResponse variable passed into the FormatAndUpload method is null.
I'm not too familiar with the promise framework in Javascript/JQuery but I was under the impression that the event should only fire on completion of the previous method.
Does anyone have any pointers in how I can correctly wait for the login to complete before attempting the POST?
what you did FormatAndUpload(authResult, data); is wrong the correct way to pass a callback is
.then(function(authResult){
FormatAndUpload(authResult, data);
}, errorCallback);
so your saveToSharepoint will be like this
function saveToSharepoint(data) {
var authority = "https://login.microsoftonline.com/common/";
var authContext = new Microsoft.ADAL.AuthenticationContext(authority);
var authResult = authContext.acquireTokenAsync("https://my.sharepoint.com", "4be098f8-2184-4831-9ef7-3d17dbbef6a0", "http://localhost:4400/services/office365/redirectTarget.html")
.then(function(authResult){
FormatAndUpload(authResult, data);
}, errorCallback);
}
Thanks for the answer Newbee Dev, you were correct in that I didn't formulate the then method correctly.
For any others who see this regarding SharePoint, I actually reformatted the code for it to work as expected, so the saveToSharepoint method looks like so:
function saveToSharepoint(data) {
var AuthenticationContext = Microsoft.ADAL.AuthenticationContext;
AuthenticationContext.createAsync("https://login.microsoftonline.com/common/")
.then(function (authContext) {
authContext.acquireTokenAsync(
"https://my.sharepoint.com", // Resource URI
"4be098f8-2184-4831-9ef7-3d17dbbef6a0", // Client ID
"http://localhost:4400/services/office365/redirectTarget.html" // Redirect URI
).then(function (authResult) {
FormatAndUpload(authResult, data);
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
}
The main thing to note is creating the AuthenticationContext asynchronously and this way, the FormatAndUpload calls after the whole login process is complete. Just thought I would post this for other people who see this regarding Sharepoint and are stuck.
Related
Hi All,
I got a scenario in which i am supposed to call a REST api that is secured by a AZURE ACTIVE DIRECTORY. Most of the code runs fine and i am able to get the token using myMSALObj.acquireTokenSilent function too.
401 ERROR COMES WHEN I SEND AJAX CALL USING THAT TOKEN, YOU CAN SEE FOLLOWING CODE
User is there in Active Directory for which i get proper token, i dont know why my ajax call fails when i send that token to rest-api, please help
<script type="text/javascript">
const msalConfig = {
auth: {
clientId: "94edf294-08ae-489f-8621-c6d98009afa8",
authority: "https://login.microsoftonline.com/c483b3c4-21a6-4c93-95ea-7436cf318a68",
redirectUri: "https://localhost:44334/",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
}
};
const myMSALObj = new Msal.UserAgentApplication(msalConfig);
function CallApi() {
// Add scopes for the id token to be used at Microsoft identity platform endpoints.
const loginRequest = {
scopes: ["User.Read"],
};
myMSALObj.loginPopup(loginRequest)
.then((loginResponse) => {
const accessTokenRequest = {
scopes: ["api://8c2b0253-f9e8-442c-bccf-b4a8bbe73b59/access_as_user"]
};
myMSALObj.acquireTokenSilent(accessTokenRequest).then((accessTokenResponse) => {
var accessToken = accessTokenResponse.accessToken;
var apiEndpoint = "https://localhost:44387/api/hello";
var bearer = "Bearer " + accessToken;
console.log("accessToken = ", accessToken);
$.ajax({
url: apiEndpoint,
type: "GET",
beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", bearer) }
}).done(function (response) {
alert("SUCCESS");
console.log("response = ", JSON.stringify(response));
}).fail(function (err) {
console.error("Error Occurred");
console.log("error = ", JSON.stringify(err));
});
})
}).catch(function (error) {
console.log(error);
});
}
</script>
Screenshot of a NEW API Code
Screenshot of JWT.ms (Access Token)
New Screenshot of JWT Token
You should not set the client ID in the appsettings.json file to the client id of your api app. It should be the client id of your client app. According to the jwt analysis diagram you provided, I think it should be: 94edf294- 08ae-489f-8621-c6xxxxxxx.
My bad, Following call was missing in my startup.cs file
app.UseAuthentication();
thanks for your help guys
Specially - #Carl Zhao, #Purushothaman #Rass Masood
I have a REST API running and I am posting some data to it using JQuery.
This is how my JQuery code looks:
$(document).ready(function () {
$('#login-form').submit(function () {
var user = $('#uname').val();
var pass = $('#pwd').val();
alert('username = ' + user);
alert('password = ' + pass);
var JSONObject = { 'userName': user, 'password': pass };
var jsonData = JSON.parse(JSONObject);
$.ajax({
url: 'http://127.0.0.1:8080/user/login',
method: 'POST',
data: { userName: user, password: pass },
dataType: 'JSON',
contentType: 'application/json',
success: function (data, status, jqXHR) {
//Do something
console.log('data = ' + data);
},
error: function (jqXHR, status, errorThrown) {
alert('error ' + errorThrown);
}
});
});
});
However, this code is unable to access the API. I do not get the expected message in the server log.
When the Submit button of the form is clicked, the browser gets reloaded and it shows the form inputs in the url. That is all.
My API is written using Java and this is the relevant method.
#RequestMapping(value = "/user/login", method = RequestMethod.POST)
public ResponseEntity<User> logUser(#RequestBody User user){
User loggedUser = loginService.authenticateUser(user);
if(loggedUser != null){
System.out.println("User found");
return new ResponseEntity<User>(loggedUser, HttpStatus.ACCEPTED);
}else{
//user does not exsits
System.out.println("User not found");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
I really can't understand what is wrong. No any error is shown. Can somebody point me out why this happens and how to fix this issue.
The issue is that the browser is reloading on submit event.
You need to add preventDefault() method like this
$("#login-form").submit(function (event) {
event.preventDefault()
//further code here
This will prevent the browser from reloading
I am new to the working with TAPE JS for testing. I have it all setup and working, and it works fine with regular tests. But I am trying to test a unique REST API based product that relies on certain calls to have been made before the next call has the information needed to have a successful call.
So here are the first two calls I am trying to get working:
var SessionId;
test('beginIqsSession', function (assert) {
assert.plan(1);
var requestData = {"ProductDataArray":{"Feid":"GIQNY","AltData":"SaneID:null","Debug":"false","PageId":"1.1"}};
request({
url: 'http://192.168.99.100/Iqs/api.php/beginIqsSession',
method: "POST",
json: requestData
}, function(error, response, json){
if(json.responseDataPayload.SessionId)
{
SessionId = json.responseDataPayload.SessionId;
assert.equal(1,1);
}
});
assert.end();
});
test('validateAddress', function (assert) {
assert.plan(2);
console.log("Retrieving validateAddress response");
var requestData = {"SessionId":SessionId,"ValidateAddressDataArray":{"PropertyStreetNumber":"20671","PropertyStreetName":"mountain vista dr","PropertyCity":"anchorage","PropertyState":"AK","PropertyZipCode":"99577"}};
console.log(SessionId);
request({
url: 'http://192.168.99.100/Iqs/api.php/validateAddress',
method: "POST",
json: requestData
}, function (error, response, body) {
if (!error) {
console.log(body);
}
else {
console.log("error: " + error)
}
});
assert.end();
});
So basically in the code above, I am trying to test beginIqsSession, wait for its response, and store a piece of data from that response that future calls require to be sent in.
in validateAddress you'll see I am trying to pass SessionId in which was returned in the previous call, but because this test is being run at the same time as the previous test, this variable is still empty. How can I make the second call, and all future calls, to wait for the previous call to run?
assert.plan apparently doesn't work in this way.
You could use the Promise API
var SessionId;
let p1 = new Promise((resolve, reject) => {
test('beginIqsSession', function (assert) {
assert.plan(1);
var requestData = {"ProductDataArray":{"Feid":"GIQNY","AltData":"SaneID:null","Debug":"false","PageId":"1.1"}};
request({
url: 'http://192.168.99.100/Iqs/api.php/beginIqsSession',
method: "POST",
json: requestData
}, function(error, response, json){
if(json.responseDataPayload.SessionId)
{
SessionId = json.responseDataPayload.SessionId;
assert.equal(1,1);
resolve(SessionId);
}
});
assert.end();
});
})
p1.then((SessionId) => {
test('validateAddress', function (assert) {
assert.plan(2);
console.log("Retrieving validateAddress response");
var requestData = {"SessionId":SessionId,"ValidateAddressDataArray":{"PropertyStreetNumber":"20671","PropertyStreetName":"mountain vista dr","PropertyCity":"anchorage","PropertyState":"AK","PropertyZipCode":"99577"}};
console.log(SessionId);
request({
url: 'http://192.168.99.100/Iqs/api.php/validateAddress',
method: "POST",
json: requestData
}, function (error, response, body) {
if (!error) {
console.log(body);
}
else {
console.log("error: " + error)
}
});
assert.end();
});
});
I have tried a myriad of different function calls, but can't seem to figure out how to trigger a download for a CSV in EmberJs.
Here is my latest code:
let endpoint = '/api/foo/';
let options = {
url: endpoint,
type: 'POST',
data: {},
dataType: 'text'
};
return new Ember.RSVP.Promise((resolve, reject) => {
options.success = function(result) {
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(result);
window.open(uri, 'foo.csv');
};
options.error = (xhr, errorThrown) => {
console.log('error');
// return Ember.run(null, reject, this.didError(xhr, xhr.status, xhr.responseJSON, 1));
};
Ember.$.ajax(options);
});
This code doesn't raise any server or client side errors. It's getting a 200 response. No javascript errors, and doesn't console log anything, so I know it's not hitting the error block. But... it won't trigger the file download on the client. Does anyone know what is missing?
I am unable to test this, but I believe your issue is with returning a new promise, whereas what you really want is to return the promise itself.
So change your code to:
let endpoint = '/api/foo/';
let options = {
url: endpoint,
type: 'POST',
data: {},
dataType: 'text'
};
return Ember.RSVP.Promise((resolve, reject) => { // note the deletion of new
options.success = function(result) {
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(result);
window.open(uri, 'foo.csv');
};
options.error = (xhr, errorThrown) => {
console.log('error');
// return Ember.run(null, reject, this.didError(xhr, xhr.status, xhr.responseJSON, 1));
};
Ember.$.ajax(options);
});
In implementing a similar piece of functionality, I went for a different route. Rather than creating an AJAX request, I create a form and submit it to the server. My API endpoint will then return the CSV in the response, with the appropriate Content-Disposition headers, and the browser will just download the file.
(Depending on your authentication scheme, you may have to include your authentication token as a value in your form data).
Example code below. You'll see I'm adding the auth token. The form's action URL is set in the markup of the page, but you could set it dynamically here if you wanted.
csvDownload () {
let form = Ember.$('#csvdownloadform')
let input = Ember.$('#csvdownloadtoken')
input.val(this.get('session').get('session.content.authenticated.token'))
form.submit()
input.val('')
form_func.val('')
},
After the update request is sent, I would like to get a success/fail response.
Regarding the response, I have to receive the one response after all update query is performed.
How to receive the one response?
The following code is my node.js server example.
Thank you!!
$.ajax({
url: "http://127.0.0.1:62590/updatingResourceList",
type: "put",
dataType: "text",
cache: false,
timeout: 30000,
data: JSON.stringify(jsonObject),
contentType: "application/json",
success: function (data) {
alert("Success updating the resource");
}, error: function (xhr, textStatus, errorThrown) {
alert(textStatus + ' : ' + errorThrown);
}
});
=========================================================================
app.put('/updatingResourceList', function (request, response) {
var resultObj = request.body;
var updatedIDList = resultObj['idList'];
// Updating the user request format
var idCounting = 0;
for(var i = 0; i < updatedIDList.length; i++) {
var latest = timestamp();
var resourceName = updatedIDList[i];
var client = dbClient.getDBClient(); // Getting Database information.
client.query('UPDATE testset SET time=? WHERE resourceName=?', [latest, resourceName], function (error, results, fields) {
if (error) { // error
console.log("MySQL : Database resource update error : " + error);
response.status(500).end();
} else { // success
console.log('MySQL : Success updating the resource : ' + resourceName);
response.status(200).end();
}
});
}
});
The problem is that you are sending back a response at each iteration of the loop. If you want a single response, then do it only after the loop. In the loop keep track of the results of the update in an array (key should be the resourceName), and send back the results in one go, perhaps as a json object.
What you need to decide, however, is how to handle if only some of the updates are successful. You either have to return an OK (status code 200), or an internal error at the end.