Slack interactive message getting invalid_payload for response_url sent back - javascript

I've been doing some work with the Slack API and with their
interactive messages
I post a message with the interactive message attachment here:
export const postMessage = (msg, channel) => {
request({
method: 'POST',
uri: 'https://slack.com/api/chat.postMessage',
headers: {
'content-type': 'application/json;charset=UTF-8',
Authorization: `Bearer ${process.env.SLACKTOKEN}`,
},
body: JSON.stringify({
token: process.env.SLACKTOKEN,
attachments: [
{
"text": "",
"fallback": "If you could read this message, you'd be choosing something fun to do right now.",
"color": "#3AA3E3",
"attachment_type": "default",
"callback_id": "command_selection",
"actions": [
{
"name": "command_list",
"text": "Choose a command",
"type": "select",
"options": [
{
"text": "Register Team",
"value": "registerTeam"
},
{
"text": "Edit Team",
"value": "editTeam"
},
{
"text": "Get By Url",
"value": "getByUrl"
},
{
"text": "Report Issue",
"value": "reportIssue"
},
{
"text": "Find Team",
"value": "findTeam"
},
{
"text": "List Teams",
"value": "listTeams"
}
]
}
]
}
],
text: msg,
channel,
as_user: true,
})
}, (err, res, body) => {
if (err) {
console.log('error posting msg: ', err);
} else {
console.log('post message to channel: ', body);
}
})
}
Slack then sends a POST request to this URL with a response_url parameter in their payload. This is where I'm getting the payload from in my code:
api.post('/interactivity', (req, res) => {
const { body } = req;
const { payload } = body;
const parsedPayload = JSON.parse(payload)
res.send(parsedPayload.response_url)
var message = {
"text": payload.user.name+" clicked: "+payload.actions[0].name,
"replace_original": false,
}
util.sendMessageToSlackResponseURL(parsedPayload.response_url, message)
})
export const sendMessageToSlackResponseURL = (responseURL, JSONmessage) => {
var postOptions = {
uri: responseURL,
method: 'POST',
headers: {
'content-type': 'application/json'
},
json: JSONmessage
}
request(postOptions, (error, res, body) => {
if (error){
console.log(error)
} else {
console.log('post message to channel: ', body);
}
})
}
For some reason though, the response_url is giving an invalid_payload error when I click on the link and I can't figure out if its the payload I'm sending in the original message I posted or something's up with the POST request that Slack sent

The issue is with utility method on line json: JSONmessage which should be body: JSONmessage
Updated code,
export const sendMessageToSlackResponseURL = (responseURL, JSONmessage) => {
var postOptions = {
uri: responseURL,
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSONmessage
}
request(postOptions, (error, res, body) => {
if (error){
console.log(error)
} else {
console.log('post message to channel: ', body);
}
})
}
Hope this works!

Related

Trying to grab the correct post id from API in order to send message to only that post

In React Javascript - how would I send a message to a post with a specific id? Here's a sample object:
{
"success": true,
"error": null,
"data": {
"post": {
"location": "Bronx, NY",
"willDeliver": false,
"messages": [],
"active": true,
"_id": "5e8d1bd48829fb0017d2233b",
"title": "Schwinn Bicycle",
"price": "3.88",
"description": "This is a 19 speed bicycle, barely used.",
"author": {
"_id": "5e8d1a02829c8e0017c20b55",
"username": "joe1234"
},
"createdAt": "2020-04-08T00:33:24.157Z",
"updatedAt": "2020-04-08T00:33:24.157Z",
"__v": 0,
"isAuthor": true
}
}
}
I must be grabbing the id incorrectly because the message isn't sending to the right post.
I have a useState initialized with an empty string to store the post id so I can pass it into the fetch URL request.
const [postId, setPostId] = useState("");
const response = await fetch(`${API_URL}/posts/${id}/messages`
Here's the code I have so far
const sendMessage = async (token, id, content) => {
try {
const response = await fetch(`${API_URL}/posts/${id}/messages`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
message: {
content: content,
},
}),
});
const data = await response.json();
alert("message successfully sent");
return data;
} catch (err) {
console.error(err);
}
};
<form
name="message"
onSubmit={(event) => {
event.preventDefault();
posts.map((post) => {
setPostId(post._id);
});
}}
<label htmlFor="content">Content: </label>
<input
type="text"
name="content"
value={messageContent}
required
onChange={(event) => {
setMessageContent(event.target.value);
}}
/>
<button
onClick={() => {
sendMessage(token, postId, messageContent);
}}
>
Send
</button>
Thanks for any hints or help!

Error response graph.microsoft.com/v1.0/me/manager

Look at my code, what am I doing wrong? I need to get https://graph.microsoft.com/v1.0/users/${uniqueName}/manager. But the request fails
But when I try to execute the https://graph.microsoft.com/v1.0/${uniqueName} query, everything goes well. What to fix so that the https://graph.microsoft.com/v1.0/users/${uniqueName}/manager request is successful?
fastify.post('/login', {
preHandler: (request, _, next) => {
if (!request.body || !request.body.username || !request.body.password) {
const error = new Error('Credentials are missing');
error.statusCode = 400;
return next(error);
}
return next();
},
}, async (request, reply) => {
const { username, password } = request.body;
const userData = await fastify.helpers.authentication.getUserTokens(username, password, azureConfig.CLIENT_SCOPE);
await replyWithTokens(fastify, reply, userData);
});
And next
const getUserTokens = async (username, password, scope) => {
const authUrl = `https://login.microsoftonline.com/${azureConfig.TENANT_NAME}/oauth2/v2.0/token`;
const body = {
client_id: azureConfig.CLIENT_ID,
client_secret: azureConfig.CLIENT_SECRET,
grant_type: 'password',
password,
scope,
username,
};
const authResponse = await fetch(authUrl, {
body: new URLSearchParams(body).toString(),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
});
if (!authResponse.ok) {
fastify.helpers.error.throwError(422, 'Authentication failed');
}
const result = await authResponse.json();
const decodedData = jwt.decode(result.access_token);
const uniqueName = String(decodedData.unique_name || '').toLowerCase();
const name = String(decodedData.upn || uniqueName).toLowerCase();
const agentAttributes = {};
if (!uniqueName) {
fastify.helpers.error.throwError(400, 'Unique name not found');
}
let recheckSan = true;
let san = name.split('#').shift();
let agent = await fastify.db.models.Agent.findOne({
where: { uniqueName },
});
let radId = '';
const graphAuthResponse = await fetch(authUrl, {
body: new URLSearchParams({
...body,
scope: 'email openid profile https://graph.microsoft.com/User.Read',
}).toString(),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
});
if (graphAuthResponse.ok) {
const graphAuthResult = await graphAuthResponse.json();
const { access_token: graphAccessToken = '' } = graphAuthResult;
// eslint-disable-next-line max-len
const graphResponse = await fetch(`https://graph.microsoft.com/v1.0/users/${uniqueName}/manager`, {
headers: {
authorization: `Bearer ${graphAccessToken}`,
'content-type': 'application/json',
},
});
if (graphResponse.ok) {
const graphResult = await graphResponse.json();
console.log(graphResult)
}
}
}
I want to receive such response
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#directoryObjects/$entity",
"#odata.type": "#microsoft.graph.user",
"id": "1111112-68cf-4896-b2d0-13b5c6264113",
"businessPhones": [
"111 111 11111"
],
"displayName": "Wer, John",
"givenName": "John",
"jobTitle": "SENIOR DEVELOPMENT ARCHITECT",
"mail": "somemail#mail.com",
"mobilePhone": "111 111 1111",
"officeLocation": "Atlanta",
"preferredLanguage": null,
"surname": "John",
"userPrincipalName": "somemail#mail.com"
}
But I get such an error response. What am I doing wrong? Thanks!
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"date": "2022-01-14T20:40:30",
"request-id": "9e2b5937-4bd0-4fdb-a1ae-1b22cef09772",
"client-request-id": "9e2b5937-4bd0-4fdb-a1ae-1b22cef09772"
}
}
}
To get the managers of other users in your organization on your behalf, you need to have User.Read.All delegated permission
Once the permission is assigned, admin consent needs to be granted for the same.
Then you would be able to fetch the managers info of other users in your organization
You can test the same in Graph Explorer first. If it is successful, you can make the changes accordingly in your JavaScript code

Gmail-API Threads.list is not returning messages in the response

I'm trying to use the Gmail-API to get all the threads from a user and to have all of the messages in that thread by using threads.list. In the gmail documentation, it states that the following is the response from hitting this endpoint:
{
"threads": [
users.threads Resource
],
"nextPageToken": string,
"resultSizeEstimate": unsigned integer
}
I have a simple function to hit this endpoint
const {google} = require('googleapis');
/**
* Lists the threads in the user's account.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
export function listThreads(auth,fn) {
const gmail = google.gmail({version: 'v1', auth});
gmail.users.threads.list({
userId: 'me',
q: 'to:abc#abc.com '
}, (err, res) => {
if (err) throw 'The API returned an error: ' + err;
// fn is a callback used to return data to the handler since
// the res object is in the callback of thread.list
fn(res)
});
}
The following is what I get as a response (I replaced the actual email with abc and replaced my token for privacy):
{
"gmail": {
"config": {
"url": "https://www.googleapis.com/gmail/v1/users/me/threads?q=to%3Aabc%40abc.com",
"method": "GET",
"headers": {
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Authorization": "Bearer 123456",
"Accept": "application/json"
},
"params": {
"q": "to:abc#abc.com"
},
"responseType": "json"
},
"data": {
"threads": [
{
"id": "173bf0efdd1f1dc4",
"snippet": "Hello abc, Attached are the screenshots of my website for the requirements. Please send me an email with all of the information I'm asking for in the forms. For the colors, here is the site to",
"historyId": "4759550"
}
],
"resultSizeEstimate": 1
},
"headers": {
"alt-svc": "h3-29=\":443\"; ma=2592000,h3-27=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"",
"cache-control": "private",
"connection": "close",
"content-encoding": "gzip",
"content-type": "application/json; charset=UTF-8",
"date": "Thu, 20 Aug 2020 01:13:07 GMT",
"server": "ESF",
"transfer-encoding": "chunked",
"vary": "Origin, X-Origin, Referer",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"x-xss-protection": "0"
},
"status": 200,
"statusText": "OK"
}
}
As you can see, the messages property of res.data.threads is completely missing. I would appreciate any guidance.
Thank You
In this case, in order to retrieve all messages from each thread, it is required to use the method of "Users.threads: get". When your script is modified, it becomes as follows.
Modified script:
const gmail = google.gmail({version: 'v1', auth});
gmail.users.threads.list(
{
userId: "me",
q: "to:abc#abc.com ",
},
(err, res) => {
if (err) throw "The API returned an error: " + err;
Promise.all(
res.data.threads.map(({ id }) => {
return new Promise((resolve, reject) => {
gmail.users.threads.get({ userId: "me", id }, (err, res) => {
if (err) rejects(err);
resolve(res.data);
});
});
})
).then((res) => {
fn(res);
});
}
);
Note:
In this modified script, it supposes that you have already been able to retrieve the email using Gmail API.
References:
-Users.threads: list
-Users.threads: get

Node fetch JSON data is not iterable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I am getting an error of TypeError: data.events is not iterable when using fetch to retrieve JSON data from an API.
I am pretty sure it is in my handling of the JSON in for (const event of data.events) from the below code but I am pulling short on finding a fix.
const data = fetch(url, {
method: 'post',
headers: new Headers({
Authorization: 'Bearer ' + bearerToken,
'Content-Type': 'application/json'
})
});
for (const event of data.events) {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: logo.original.url,
cache,
store,
createNode,
createNodeId
});
} catch (error) {
console.warn('error creating node', error);
}
}
The JSON when requested in Postman is returned as
{
"pagination": {
...
},
"events": [
{
"name": "Example One",
"logo": {
"original": {
"url": "exampleURL"
}
}
},
{
"name": "Example Two",
"logo": {
"original": {
"url": "exampleURL"
}
}
}
],
"location": {
...
}
}
The goal is to createRemoteFileNode for each event from logo.original.url
fetch() returns a promise so data.events does not exist until the fetch promised is resolved. Edit your code this way:
fetch(url, {
method: 'post',
headers: new Headers({
Authorization: 'Bearer ' + bearerToken,
'Content-Type': 'application/json'
})
}).then(function(data){
for (const event of data.events) {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: logo.original.url,
cache,
store,
createNode,
createNodeId
});
} catch (error) {
console.warn('error creating node', error);
}
}
});

Wit.ai - sending pictures via Facebook Messenger Send API

I need my Wit.ai chat bot to respond to certain messages with images, and since I've refactored my code to match the latest messenger example in the node-wit SDK I can't figure out how to do so.
Previously this FB message function worked for me:
var newMessage = function (recipientId, msg, atts, cb) {
var opts = {
form: {
recipient: {
id: recipientId
},
}
}
if (atts) {
var message = {
attachment: {
"type": "image",
"payload": {
"url": msg
}
}
}
} else {
var message = {
text: msg
}
}
opts.form.message = message
newRequest(opts, function (err, resp, data) {
if (cb) {
cb(err || data.error && data.error.message, data)
}
})
}
Now I've updated to the node-wit SDK messenger example:
const fbMessage = (id, text) => {
const body = JSON.stringify({
recipient: { id },
message: { text },
});
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
Which I've modified like this to try and make image replies work:
const fbMessage = (id, text, atts) => {
if (atts) {
var body = {
attachment: {
"type": "image",
"payload": {
"url": { text }
}
},
};
} else {
var body = JSON.stringify({
recipient: { id },
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
Text messages are being sent as normal, but when I try to send an image attachment, my image url references are just being sent as strings.
The FB Messenger Send API reference is here
Any help would be greatly appreciated!
Got it working with this:
const fbMessage = (id, text) => {
var x = text.substring(0,4);
if (x == 'http') {
var body = JSON.stringify({
recipient: { id },
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});
} else {
var body = JSON.stringify({
recipient: { id },
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
*NB - This obviously won't work if you plan on sending text replies that are just urls i.e. 'http://example.com'. To get around this you can put any symbol in front of the url address in your message like so: '> http://example.com' and links will work fine.

Categories

Resources