I trying to respond to a call in Teams but actually I'm not getting a respond from the bot.
First I get access_token from Graph API.
Then I have a route that intercept bot calls.
app.post("/api/call", function(req, res) {
if (j === 1) {
j = j + 1;
res.status(204).send();
} else {
var answerbody = {
callbackUri: "https://8a73b7ad.ngrok.io/api/call",
acceptedModalities: ["audio"],
mediaConfig: {
"#odata.type": "#microsoft.graph.serviceHostedMediaConfig",
preFetchMedia: [
{
uri: "https://cdn.contoso.com/beep.wav",
resourceId: "1D6DE2D4-CD51-4309-8DAA-70768651088E"
},
{
uri: "https://cdn.contoso.com/cool.wav",
resourceId: "1D6DE2D4-CD51-4309-8DAA-70768651088F"
}
]
}
};
POST(
"https://graph.microsoft.com/beta/" + req.body.resource + "/answer",
answerbody
)
.then(
data => console.log(data) // I get undefined
)
.catch(function(err) {
console.log("err " + err);
res.status(200).send();
});
}
});
Here's POST function
function POST(url, BB) {
return new Promise(function(resolve, reject) {
var options = {
url: url,
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Bearer " + token
},
body: BB,
json: true
};
request(options)
.then(function(body) {
resolve(body);
})
.catch(function(err) {
reject(err);
});
});
}
As mentionned in documentation , Server sould first reply 204 in order to get response in Graph API protocol.
Actually I don't get a response. Bot still ringing until It gets voice message : " You can't talk to the bot just yet , we are working on it".
As mentioned in Teams API documentation, I should get callback with the ressource id and other information to be able to answer to the call.
So I use my POST function to answer. but here I don't get any 202 Accepted response as indicated in docs, instead I get more than one callback with different ressource ids, then after some seconds I get the voice message.
The solution is to change acceptedModalities: ["audio"]
to acceptedModalities: ["Audio"]
Related
I was able to delete Grafana dashboard through its delete API from Postman but when I try deleting it through NodeJS code, it is not working. I get status as 200 from the code but the response body which I am getting is different than the Postman one.
I am using this delete API of grafana - grafana_host_url/api/dashboards/uid/:uid
and my code function is like this -
function deleteGrafana(req) {
return new Promise((resolve, reject) => {
console.log("Inside Delete Grafana")
var dashbord_api_url = req.grafana_host_url + process.env.GRAFANA_DASHBOARD_DELETE_API_URL + req.uid
var api_token = "Bearer " + req.grafana_api_key
console.log("URL:",dashbord_api_url)
console.log("api token:",api_token)
var callOptions = {
'method': 'DELETE',
'url': dashbord_api_url,
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': api_token
}
};
request.get(callOptions, (error, response) => {
if (error) {
throw new Error(error)
}
console.log("deleteGrafana Response" + response.body);
var result = {};
result.status = response.statusCode
console.log("Result Status code:",result.status)
resolve(result)
});
});
}
My response when I run it, is something like this -
deleteGrafana Response{"meta":{"type":"db","canSave":true,"canEdit":true,"canAdmin":true,"canStar":true,"canDelete":true,"slug":"sampletest","url":"/d/najkl-oo/sampletest","expires":"0001-01-01T00:00:00Z","created":"2022-12-29T11:43:00Z","updated":"2022-12-29T11:43:01Z","updatedBy":"Anonymous","createdBy":"Anonymous","version":2,"hasAcl":false,"isFolder":false,"folderId":0,"folderUid":"","folderTitle":"General","folderUrl":"","provisioned":false,"provisionedExternalId":"","annotationsPermissions":{"dashboard":{"canAdd".....
Ideal response should be as per actual grafana response for this api as something like this -
{
"id": xx,
"message": "Dashboard deleted",
"title": "sample test"}
What should I do to resolve this, so my delete functionality works properly?
When I check the grafana instance and browse the folders, the dashboard is still there.
Just debugged more and saw some other functions. Changing request.get in request.get(callOptions, (error, response) => {
to request.delete in code worked and gave the desired response.
I'm trying to pass JWT token and data fields via Jquery and then consume those values in Flask.
So, my client side query looks like this:
function getData() {
var data = {
UserPoolId : 'AWS CognitoUser Pool Id',
ClientId : 'AWS CognitoUser client Id'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
console.log(cognitoUser.signInUserSession.accessToken.jwtToken);
//
$.ajax({
url: "/api/v1/count",
type: "POST",
headers: { "X-Test-Header": cognitoUser.signInUserSession.accessToken.jwtToken },
// data: JSON.stringify(data),
data: JSON.stringify("{'UserPoolId': 'XXXX','ClientId': 'XXXX'}"),
contentType: 'application/json; charset=utf-8',
error: function(err) {
switch (err.status) {
case "400":
// bad request
break;
case "401":
// unauthorized
break;
case "403":
// forbidden
break;
default:
//Something bad happened
break;
}
},
success: function(data) {
console.log(data);
}
});
//
});
}
Now, in my serverside flask:
I tried to catch the token value using below: which is not working
#app.route("/api/v1/count", methods=["GET", "POST"])
def get_data_count():
if 'X-Test-Header' in request.headers:
headers = request.headers
app.logger.info(headers)
auth = headers.get("X-Test-Header")
app.logger.info('testing info log' + auth)
Also I tried to catch the data fields , using result = request.get_json() also not working.
I tried to inspect in chrome, and I don't see these values being added to the request header.
Can anyone suggest to me if I'm doing it correctly while passing the values from client to server? I also don't see console.log(cognitoUser.signInUserSession.accessToken.jwtToken) in the console log.
if not can anyone suggest to me, how to fix it?
I have an AWS Lambda function which triggers https request to Google API. I want the function to be awaitable, so that it does not end immediately, but only after getting response from Google API.
Yes, I know I pay for the execution, but this will not be called often, so it is fine.
The problem is that the http request does not seem to fire correctly. The callback is never executed.
I have made sure that the async/await works as expected by using setTimeout in a Promise. So the issue is somewhere in the https.request.
Also note that I am using Pulumi to deploy to AWS, so there might be some hidden problem in there. I just can't figure out where.
The relevant code:
AWS Lambda which calls the Google API
import config from '../../config';
import { IUserInfo } from '../../interfaces';
const https = require('https');
function sendHttpsRequest(options: any): Promise<any> {
console.log(`sending request to ${options.host}`);
console.log(`Options are ${JSON.stringify(options)}`);
return new Promise(function (resolve, reject) {
console.log(` request to ${options.host} has been sent A`);
let body = new Array<Buffer>();
const request = https.request(options, function (res: any) {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
if (res.statusCode != 200) {
reject(res.statusCode);
}
res.on('data', (data: any) => {
console.log(`body length is ${body.length}`);
console.log('data arrived', data);
body.push(data);
console.log('pushed to array');
console.log(data.toString());
});
});
request.on('end', () => {
console.error('Request ended');
// at this point, `body` has the entire request body stored in it as a string
let result = Buffer.concat(body).toString();
resolve(result);
});
request.on('error', async (err: Error) => {
console.error('Errooooorrrr', err.stack);
console.error('Errooooorrrr request failed');
reject(err);
});
request.end();
console.log(` request to ${options.host} has been sent B`);
});
}
/**
* AWS Lambda to create new Google account in TopMonks domain
*/
export default async function googleLambdaImplementation(userInfo: IUserInfo) {
const payload = JSON.stringify({
"primaryEmail": userInfo.topmonksEmail,
"name": {
"givenName": userInfo.firstName,
"familyName": userInfo.lastName
},
"password": config.defaultPassword,
"changePasswordAtNextLogin": true
});
const resultResponse: Response = {
statusCode: 200,
body: 'Default response. This should not come back to users'
}
console.log('Calling google api via post request');
try {
const options = {
host: 'www.googleapis.com',
path: '/admin/directory/v1/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': payload.length.toString()
},
form: payload
}
const responseFromGoogle = await sendHttpsRequest(options);
console.log('responseFromGoogle', JSON.stringify(responseFromGoogle));
}
catch (err) {
console.log('Calling google api failed with error', err);
resultResponse.statusCode = 503;
resultResponse.body = `Error creating new Google Account for ${userInfo.topmonksEmail}.`;
return resultResponse;
}
console.log('request to google sent');
return resultResponse;
}
The problem is that the http request does not seem to fire correctly. The callback is never executed.
I believe this part of the issue is related to some combination of (a) potentially not actually sending the https request and (b) not using the correct callback signature for https.request. See the documentation at https://nodejs.org/api/https.html#https_https_request_options_callback for details on both of these.
Use node-fetch package
The following example works for me using node-fetch:
import * as aws from "#pulumi/aws";
import fetch from "node-fetch";
const api = new aws.apigateway.x.API("api", {
routes: [{
method: "GET", path: "/", eventHandler: async (ev) => {
const resp = await fetch("https://www.google.com");
const body = await resp.text();
return {
statusCode: resp.status,
body: body,
}
},
}],
})
export const url = api.url;
Pulumi complains, it something like "Can not serialize native function" or something like that. The problematic part is that node-fetch relies on Symbol.iterator
As noted in the comments, some of the conditions that can lead to this are documented at https://pulumi.io/reference/serializing-functions.html. However, I don't see any clear reason why this code would hit any of those limitations. There may be details of how this is used outside the context of the snippet shared above which lead to this.
I'm trying to build a CLI that uses the GitHub api. I instantly run into a road block. Although I've read the introductory docs up and down, I don't see what is wrong in the following code.
var userData = require('../userData');
var request = require('request');
module.exports = {
hitEndpoint: function() {
var username = "<redacted_user_name>",
password = "<redacted_password>",
auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
var options = {
method: 'get',
url: " https://api.github.com/<redacted_user_name>",
headers: {
"Authorization": auth,
"User-Agent": "<redacted_whatever_doesnt_matter>"
}
}
request(options, function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
},
}
prints:
error: null
statusCode: 404
body: {"message":"Not Found","documentation_url":"https://developer.github.com/v3"}
To get your own profile you'll want to hit the authenticated user endpoint, you shouldn't replace this with your own username, GitHub will know who you are based on your authentication string:
https://api.github.com/user
To get another user's profile you'll want to hit the users endpoint:
https://api.github.com/users/:username
I'm trying to implement https://developers.podio.com/doc/items/add-new-item-22362 Podio API addItem call in a nodejs module. Here is the code:
var _makeRequest = function(type, url, params, cb) {
var headers = {};
if(_isAuthenticated) {
headers.Authorization = 'OAuth2 ' + _access_token ;
}
console.log(url,params);
_request({method: type, url: url, json: true, form: params, headers: headers},function (error, response, body) {
if(!error && response.statusCode == 200) {
cb.call(this,body);
} else {
console.log('Error occured while launching a request to Podio: ' + error + '; body: ' + JSON.stringify (body));
}
});
}
exports.addItem = function(app_id, field_values, cb) {
_makeRequest('POST', _baseUrl + "/item/app/" + app_id + '/',{fields: {'title': 'fgdsfgdsf'}},function(response) {
cb.call(this,response);
});
It returns the following error:
{"error_propagate":false,"error_parameters":{},"error_detail":null,"error_description":"No matching operation could be found. No body was given.","error":"not_found"}
Only "title" attribute is required in the app - I checked that in Podio GUI. I also tried to remove trailing slash from the url where I post to, then a similar error occurs, but with the URL not found message in the error description.
I'm going to setup a proxy to catch a raw request, but maybe someone just sees the error in the code?
Any help is appreciated.
Nevermind on this, I found a solution. The thing is that addItem call was my first "real"-API method implementation with JSON parameters in the body. The former calls were authentication and getApp which is GET and doesn't have any parameters.
The problem is that Podio supports POST key-value pairs for authentication, but doesn't support this for all the calls, and I was trying to utilize single _makeRequest() method for all the calls, both auth and real-API ones.
Looks like I need to implement one for auth and one for all API calls.
Anyway, if someone needs a working proof of concept for addItem call on node, here it is (assuming you've got an auth token beforehand)
_request({method: 'POST', url: "https://api.podio.com/item/app/" + app_id + '/', headers: headers, body: JSON.stringify({fields: {'title': 'gdfgdsfgds'}})},function(error, response, body) {
console.log(body);
});
You should set content-type to application/json
send the body as stringfied json.
const getHeaders = async () => {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
};
const token = "YOUR APP TOKEN HERE";
headers.Authorization = `Bearer ${token}`;
return headers;
}
const createItem = async (data) => {
const uri = `https://api.podio.com/item/app/${APP_ID}/`;
const payload = {
fields: {
[data.FIELD_ID]: [data.FIELD_VALUE],
},
};
const response = await fetch(uri, {
method: 'POST',
headers: await getHeaders(),
body: JSON.stringify(payload),
});
const newItem = await response.json();
return newItem;
}