How to wait for async function response in outlook addin - outlook

I am working on developing outlook addin using Javascript (newbie to JS).
After collecting all sendmail details, we have post the details to server and wait for the result.
Based on the result, the sendmail should be allowed / blocked.
getAllMailDetails() is the callback for ItemSend event in addin manifest file and outlook is calling my addin function when a new mail is sent.
But allowBlockMail() is immediately called without waiting for the async.
Since Javascript is single threaded (https://www.freecodecamp.org/news/async-await-javascript-tutorial/), how do I wait for the response to be included ?
let serverresp = "empty client";
function getAllMailDetails(event) {
runfetch(event);
allowBlockMail(event);
}
function allowBlockMail(event) {
item = Office.context.mailbox.item;
item.subject.getAsync(
{ asyncContext: event },
function (asyncResult) {
item.notificationMessages.addAsync('NoSend', { type: 'errorMessage', message: serverresp });
asyncResult.asyncContext.completed({ allowEvent: false });
return;
}
)
}
async function runfetch(event) {
let user = {
name: 'Addin Fetch 1234',
surname: 'Smith'
};
serverresp = "before POST";
try{
let response = await fetch('https://localhost:4431/something.aspx', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
body: JSON.stringify(user)
});
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
serverresp = await response.text();
} else {
serverresp = "http-error";
}
}
catch(err) {
serverresp = "caught exception";
}
}

One of the simplest ways is in the getAllMailDetails function you just need to call the single function:
function getAllMailDetails(event) {
runfetch(event);
}
And when the fetch is done you may call the other one:
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
serverresp = await response.text();
// your processing results
allowBlockMail(event);
} else {
serverresp = "http-error";
}

Related

Async Lambda function returning null on calling DynamoDB

I am new to async functions and promises. I have written a Lambda function which queries a DynamoDB table and returns the result. The code is executing inside the callback success block and I am able to see the response in the log from the console.log(res) line. However the Lambda response is always showing as null, i.e. the response object below is not returned at all. I was able to make this work using a Synchronous Lambda function using a callback to return the data. Can you please suggest what I may be doing incorrectly.
const doc = require('dynamodb-doc');
var dynamodbclient;
const tablename = process.env.TABLE_NAME;
exports.handler = async(event) => {
if (!dynamodbclient) {
dynamodbclient = new doc.DynamoDB();
}
let id = event.params.id;
let queryparams = {
TableName: 'table-name',
Key: { id: id }
};[![enter image description here][1]][1]
var getItemsCallback = (err, res) => {
console.log('inside');
if (err) {
}
else {
console.log('success');
console.log(res);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
}
};
var item = await dynamodbclient.getItem(queryparams, getItemsCallback).promise();
};
Your callback is still executing after the promise resolves, so the lambda will terminate and your callback will not finish.
Try:
try {
const item = await dynamodbclient.getItem(queryparams).promise();
} catch (err) {}
console.log('success');
console.log(item);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;

Cypress not waiting for Before block to complete

I am trying to achieve the following functionality
Before Block : Call the Cy.visit("/login") and call a Function which will trigger a REST API and process the REST API response and set the local storage.
Only after the local storage is set click on "My Account" Link
Here is the source Code I am trying.
import * as subscriberHelpers from '../../../helpers/subscriberHelpers';
import * as localStorage from '../../../helpers/localStorage';
describe('testCode', () => {
before((done) => {
cy.visit('/login', {
timeout: 10000,
onLoad: () => {
localStorage.write("CD-Environment", Cypress.env('defaultEnvironment'));
localStorage.write("CD-Language", "en-US");
localStorage.write("CD-SystemId", "85788485-e411-48a9-b478-610c1285dc1a");
}
})
subscriberHelpers.createSubscriber().then(()=>{
done();
})
})
it('sClick on my account link', () => {
cy.get('.c-header-listItem > .c-link').contains("My Account").click();
})
})
Here is the code to createSubscriber function
export function createSubscriber() {
let URL = `SOME URL`;
let body = {
Some Body
}
return new Promise((resolve, reject) => {
request.subscriberServiceRequest(URL, body).then((response) => {
if (response.status === 200 && ("SessionId" in response.body)) {
localStorage.write("CD-SessionId", response.body.SessionId);
localStorage.write("CD-SubscriberId", response.body.Subscriber.Id);
resolve();
}
else if (response.status === 200 && ("Fault" in response.body)) {
reject(response.body.Fault.Message);
}
})
})
}
Here is the code to subscriber Service request function
export function subscriberServiceRequest(url, body, headers = null) {
let defaultHeaders = { "CD-SystemId": "85788485-e411-48a9-b478-610c1285dc1a" }
if (headers != null) {
defaultHeaders = addHeaders(defaultHeaders, headers);
}
return new Cypress.Promise((resolve, reject) => {
cy.request({
url: url,
method: 'POST',
body: body,
headers: defaultHeaders
}).then((response) => {
resolve(response);
});
})
}
When I try Executing the code I am getting following error in cypress
But the element existing in the UI
Questions:
Why I am getting the error
How to call more than one async functions
in before block
How to tell cypress to wait till the functions on
before block get processed meaning not only wait till receiving the
response but wait till the response got processed in the THEN block
To answer your first question:
Why I am getting the error
.contains() specifically searches for elements within but not including the tag it is called on. In other words, someElement.contains("My Account") will not match someElement.
What you should have instead is this:
cy.get('.c-header-listItem').contains("My Account").click();
Or simply:
cy.contains("My Account").click();

submitAdapterAuthentication not working

I have been trying to do a specific operation once I receive the submitAdapterAuthentication from the challenge handler and I could not do any operation because my code it does not even compile through it. I am using the submitAdapterAuthentication in one method of my angular service. The method looks like this:
login: function (user, pass) {
//promise
var deferred = $q.defer();
//tempuser
tempUser = {username: user, password: pass};
userObj.user = user;
checkOnline().then(function (onl) {
if (onl) { //online
console.log("attempting online login");
var auth = "Basic " + window.btoa(user + ":" + pass);
var invocationData = {
parameters: [auth, user],
adapter: "SingleStepAuthAdapter",
procedure: "submitLogin"
};
ch.submitAdapterAuthentication(invocationData, {
onFailure: function (error) {
console.log("ERROR ON FAIL: ", error);
},
onConnectionFailure: function (error) {
console.log("BAD CONNECTION - OMAR", error);
},
timeout: 10000,
fromChallengeRequest: true,
onSuccess: function () {
console.log("-> submitAdapterAuthentication onSuccess!");
//update user info, as somehow isUserAuthenticated return false without it
WL.Client.updateUserInfo({
onSuccess: function () {
//return promise
deferred.resolve(true);
}
});
}
});
} else { //offline
console.log("attempting offline login");
deferred.resolve(offlineLogin());
}
uiService.hideBusyIndicator();
});
uiService.hideBusyIndicator();
return deferred.promise;
}
where ch is
var ch = WL.Client.createChallengeHandler(securityTest);
and checkOnline is this function that checks whether the user is online or not:
function checkOnline() {
var deferred = $q.defer();
WL.Client.connect({
onSuccess: function () {
console.log("** User is online!");
deferred.resolve(true);
},
onFailure: function () {
console.log("** User is offline!");
deferred.resolve(false);
},
timeout: 1000
});
return deferred.promise;
}
Finally this is the "submitLogin" procedure that I have in my SingleStepAuthAdapter.js. SingleStepAuthAdapter is the name of the adapter.
//-- exposed methods --//
function submitLogin(auth, username){
WL.Server.setActiveUser("SingleStepAuthAdapter", null);
var input = {
method : 'get',
headers: {Authorization: auth},
path : "/",
returnedContentType : 'plain'
};
var response = "No response";
response = WL.Server.invokeHttp(input);
WL.Logger.info('Response: ' + response.isSuccessful);
WL.Logger.info('response.responseHeader: ' + response.responseHeader);
WL.Logger.info('response.statusCode: ' + response.statusCode);
if (response.isSuccessful === true && (response.statusCode === 200)){
var userIdentity = {
userId: username,
displayName: username,
attributes: {
foo: "bar"
}
};
WL.Server.setActiveUser("SingleStepAuthAdapter", userIdentity);
return {
authRequired: false
};
}
WL.Logger.error('Auth unsuccessful');
return onAuthRequired(null, "Invalid login credentials");
}
So I am trying to send a promise to my controller in order to redirect the user to another page but the promise is not being returned as the challenge handler is not even working.
And by the way, I have followed this tutorial: https://medium.com/#papasimons/worklight-authentication-done-right-with-angularjs-768aa933329c
Does anyone know what this is happening?
Your understanding of the Challenge Handler and mine are considerably different.
Although the
ch.submitAdapterAuthentication()
is similar in structure to the standard adapter invocation methods I have never used any callbacks with it.
I work from the IBM AdapteBasedAuthentication tutorial materials
The basic idea is that your challenge handler should have two callback methods:
isCustomResponse()
handleChallenge()
You will see these functions invoked in response to your submission.
I suggest that start by looking at those methods. I can't comment on the ionic example you reference, but I have myself used angular/ionic with the authentication framework and challenge handlers. My starting point was the IBM material I reference above.

How make nested http query in AngularJs?

Iam build single page app in AngularJs,and I need call Facebook UI dialog.And if user click 'ok',or 'cancel',successReport methos not call immediately.This method call after i click on any button in page,or link.Similar to internal queue
service.showStreamDialog=function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
reportService.successReport(newCardSentId,newCardSentId,resp.post_id);
} else {
reportService.cancelReport(newCardSentId);
}
});
}
};
// in other file
var successReport=function(cardId,cardSentId,postId){
var defered = $q.defer();
$http.post(reportUrl,$.param({
cardId:cardId,
cardSentId:cardSentId,
postId:postId,
accessToken: ACCESS_TOKEN
}))
.success(function(data){
defered.resolve(data);})
.error(function(data){
defered.reject(data);
});
return defered.promise;
};
I found problem. It was in integration facebook api in my app.I add $rootScope.$apply call,
and all working as i expected
service.showStreamDialog = function (json) {
if (json.stream) {
var newCardSentId = json.cardSentId;
FB.ui(json.stream, function (resp) {
if (resp && resp.post_id) {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_SUCCESS', {cardSentId: newCardSentId,post_id:resp.post_id});
});
} else {
$rootScope.$apply(function () {
$rootScope.$broadcast('CARD_SENT_CANCEL', {cardSentId: newCardSentId});
});
}
});
}
};

Winjs get request failing to return data

I encountered a strange problem. In my app I have the following code
WinJS.xhr({
url: 'http://bdzservice.apphb.com/api/Route?fromStation=София&toStation=Варна&date=30/08/2013&startTime=00:00&endTime=24:00'
}).then(function (success)
{
console.log(success);
},
function (error)
{
console.log(error);
}
);
The problem is I get an empty response text (with status 200). The Url I provided returns data through the browser and other rest clients, but in the app I get no data. Where might be the problem?
You need to encode query string parameters via encodeURIComponent (browser does this for you automatically when pasting url).
Following code will do the trick:
function serialize (obj) {
var str = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
return str.join("&");
};
var request = {
fromStation: 'София',
toStation: 'Варна',
date: '30/08/2013',
startTime: '00:00',
endTime: '24:00'
};
WinJS.xhr({
url: 'http://bdzservice.apphb.com/api/Route?' + serialize(request)
}).then(function(success) {
console.log(success);
},
function(error) {
console.log(error);
}
);

Resources