I'm attempting to invoke my api which is self hosted via ngrok. ngrok is working correctly because I can open the external https site in my browser and it loads up.
So, what do I have
slack form:
var request = require('request');
var RegisterMsgBuilder = function () { }
RegisterMsgBuilder.prototype.build = function (data) {
return {
"text": "Would you like to play a game?",
"attachments": [
{
"text": "Choose a game to play",
"fallback": "You are unable to choose a game",
"callback_id": "wopr_game",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "game",
"text": "Chess",
"type": "button",
"value": "chess"
},
{
"name": "game",
"text": "Falken's Maze",
"type": "button",
"value": "maze"
},
{
"name": "game",
"text": "Thermonuclear War",
"style": "danger",
"type": "button",
"value": "war",
"confirm": {
"title": "Are you sure?",
"text": "Wouldn't you prefer a good game of chess?",
"ok_text": "Yes",
"dismiss_text": "No"
}
}
]
}
]
}
};
exports.RegisterMsgBuilder = RegisterMsgBuilder;
this produces a form in slack with 3 buttons.
I've set up interactive components with the following url:
https://xyz.ngrok.io/api/values
this url points to a new asp.net webapi project. I've not changed anything in here. Its got a controller which looks like:
namespace WebApplication2.Controllers
{
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post()
{
int x = 66;
}
}
}
clicking on a button in my slack message does nothing. How come?
Primarily, you haven't given any kind of response for the API to act on. All your controller seems to do on receiving a POST is set x equal to 66.
When someone clicks that button in-channel, a POST request will be made to your action URL. It'll contain some information about the button clicked, the original message, etc (https://api.slack.com/interactive-messages#responding). You don't seem to be pulling the values from the POST your app receives at all - you'll definitely need to do that.
Related
I'm building a slack app using the slack Bolt API, and I want to open modals from my App's home page when a button on the home page is clicked.
Here's the relevant bit of the action listener that is connected to the button:
app.action("follow-users-button", async ({ ack, payload, client }) => {
await ack();
console.log("app_home opening keyusermodal");
// await block_actions.unfollowKeyuser(action);
console.log("payload = " + JSON.stringify(payload));
await client.views.open({
trigger_id: payload.trigger_id,
Here's what I get on my terminal when I click that button:
payload = {"action_id":"follow-users-button","block_id":"2JW","text":{"type":"plain_text","text":"Users","emoji":true},"value":"click_me_123","type":"button","action_ts":"1642280065.631917"}
[ERROR] bolt-app missing required field: trigger_id
The JSON there is the action payload.
However, according to the Slack docs, this payload should be much larger. Here's the sample payload from Slack's Block Kit Builder:
{
"type": "block_actions",
"user": {
"id": "U02NF0A8D9T",
"username": "person",
"name": "person",
"team_id": "T02NTJ0UDP3"
},
"api_app_id": "A02",
"token": "Shh_its_a_seekrit",
"container": {
"type": "message",
"text": "The contents of the original message where the action originated"
},
"trigger_id": "12466734323.1395872398",
"team": {
"id": "T02NTJ0UDK3",
"domain": "4most-r637660"
},
"enterprise": null,
"is_enterprise_install": false,
"state": {
"values": {}
},
"response_url": "https://www.postresponsestome.com/T123567/1509734234",
"actions": [
{
"type": "button",
"block_id": "QdL",
"action_id": "button-action",
"text": {
"type": "plain_text",
"text": "Click Me",
"emoji": true
},
"value": "click_me_123",
"action_ts": "1642279809.506518"
}
]
}
As you can see, I'm only receiving the actions element in my payload. Where's the rest of it? Why isn't it coming over? I need the trigger_id to open a modal (not having it causes the error), and getting things like user_id would be extremely helpful for my app.
Thanks in advance!
When working with the Bolt JS framework, the expected way to parse the action payload to get the trigger id is body.trigger_id.
I have a bot application which I installed in my team, using team scope. Now when this application is uninstalled from team is there any event I can get/monitor?
I was going over the Microsoft documentation and tried following piece of code. According to this onTeamsMembersRemovedEvent is called when bot or a member is removed.
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsMembersRemovedEvent(async (membersRemoved: ChannelAccount[], teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
let removedMembers: string = '';
console.log(JSON.stringify(membersRemoved));
membersRemoved.forEach((account) => {
removedMembers += account.id + ' ';
});
const name = !teamInfo ? 'not in team' : teamInfo.name;
const card = CardFactory.heroCard('Account Removed', `${removedMembers} removed from ${teamInfo.name}.`);
const message = MessageFactory.attachment(card);
await turnContext.sendActivity(message);
await next();
});
}
}
But for me I do not receive this event when I remove the bot application. I remove the bot application manually from inside the apps by choosing uninstall.
When uninstalled the app by navigating to More options > Manage teams > Apps > Uninstall , teamMemberRemoved event got fired and got correct response.
{
"membersRemoved": [
{
"id": "28:aXXXXX04-e293-447c-951f-6a6971b3b66b"
}
],
"type": "conversationUpdate",
"timestamp": "2021-10-19T15:24:45.9499395Z",
"id": "f:e0d2c276-XXXXX-5d74-73ad-3c67b9b0ae4f",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer/",
"from": {
"id": "29:1qanOqiaR5gWE-aWoYPdYjB--mUmmVQFGddHxyb37WXc4FI-eD62pSxBJYoXXXXXeGyFlpiTzRd-fTCiBmNbeuQg",
"aadObjectId": "XXXXXc4d0-XXXXX-4154-a85f-a89cd77aefa8"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"tenantId": "3XXXXXef-XXXXX-4d60-XXXXX-0aXXXXX693df",
"id": "19:XXXXX53a099498f9e08679e58f1f7fc#thread.tacv2"
},
"recipient": {
"id": "28:aXXXXX-e293-XXXXX-951f-6a6971b3b66b",
"name": "XXXXX"
},
"channelData": {
"team": {
"aadGroupId": "XXXXXf3-fa01-XXXXX-bb62-201225dce9e4",
"name": "XXXXX",
"id": "19:XXXXX099498f9e08679eXXXXXf7fc#thread.tacv2"
},
"eventType": "teamMemberRemoved",
"tenant": {
"id": "36a708ef-XXXX-4d60-9de0-XXXXXXdf"
}
}}
I have a skill, I'm trying to test it with the "test" function in alexa developer console. If I give the invocation name, it gets recognized to be the specific intent, but the response doesn't match. (It might be something glaringly obvious that I just can't notice anymore.)
I have a LaunchRequest type, it works with the invocation name.
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
welcomeMessage = `updated welcome`;
return handlerInput.responseBuilder
.speak(welcomeMessage)
.reprompt(helpMessage)
.getResponse();
},
};
(welcomeMessage is declared outside, this was just testing if the issue was giving it new value)
However, when it comes to an intent based on user input (in this case TestIntent, the user input is "is the skill working"), it just doesn't work.
TestIntent's code is the same as LaunchRequest, except the intent type&name check
const request = handlerInput.requestEnvelope.request;
return (request.type === "IntentRequest" &&
request.intent.name === "TestIntent");
The alexa skill's json input recognizes the input as a TestIntent
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.601d2e89-71c1-417e-b878-790afc6f79f4",
"timestamp": "2019-08-12T07:01:38Z",
"locale": "en-US",
"intent": {
"name": "TestIntent",
"confirmationStatus": "NONE"
},
"dialogState": "STARTED"
}
But the response is just "I am sorry, but I do not know that. Can you repeat that?"
You need to create your custom intent with utterances.
Login to https://developer.amazon.com
Create your skill and add your utterances which will map to specific intent.
Sample:
{
"interactionModel": {
"languageModel": {
"invocationName": "mySkill",
"intents": [
{
"name": "TestIntent",
"slots": [
{
"name": "name",
"type": ""
}
],
"samples": [
"test me", // This would be your utterance to identify intent
"testing you" // You can have multiple
]
},
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.NoIntent",
"samples": []
}
]
}
}
}
Below is the walkthrough to the developer account
1) Create your intent
2) Create your utterances
And then just build your modal. Your Skill needs to be linked to your lambda function.
Hope this help!
======UPDATE=====
Need to return card response
response = {
outputSpeech: {
type: "PlainText",
text: output
},
card: {
type: "Simple",
title: title,
content: output
},
shouldEndSession: shouldEndSession
};
Using aw-sdk: (Sample)
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
}
I understand that adaptive cards are down-rendered as image on channels that does not support them. I just want to know how to either remove or set the "Title" element as shown on the fb channel:
The AdaptiveCard.Title element is deprecated and I did try setting that, it did not have any effect.
Here is my sample json:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"id": "Title",
"horizontalAlignment": "Center",
"size": "Large",
"weight": "Bolder",
"text": "See results on our website!"
},
{
"type": "Image",
"horizontalAlignment": "Center",
"url": "mylogo.png",
"size": "Stretch"
},
{
"type": "TextBlock",
"id": "Subtitle",
"horizontalAlignment": "Center",
"size": "ExtraLarge",
"text": "This channel does not allow us to display your results. Click the button to view it on our website.",
"wrap": true
}
],
"actions": [
{
"type": "Action.OpenUrl",
"id": "OpenUrl",
"title": "Take me there!"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
Unfortunately, when the BotFramewrok renders the card into an image for Facebook Messenger it adds the title above the actions which is strange. The only way to get rid of it is to remove the action from the card, which defeats its purpose in this case. An alternative is to send a Facebook Button Template in the activity's channel data instead of the adaptive card when the user is on Facebook Messenger. For more details checkout the Facebook Documentation on Button Templates and the code snippet below.
Screenshot
Bot Code - Node
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
if (turnContext.activity.channelId === 'facebook') {
await turnContext.sendActivity({
channelData: {
"attachment": {
"type": "template",
"payload": {
"template_type":"button",
"text":"This channel does not allow us to display your results. Click the button to view it on our website.",
"buttons":[{
"type":"web_url",
"url":"https://www.microsoft.com",
"title":"Take me there!"
}]
}
}
}
});
} else {
await turnContext.sendActivity({
attachments: [this.createAdaptiveCard()],
});
}
}
}
Hope this helps!
I had the same problem but I find an alternative using HeroCard.
If you are developing it with C# there it goes the code:
// first of all check if it is Facebook channel
// note that Channels is from Microsoft.Bot.Connector, the old one is deprecated.
if (turnContext.Activity.ChannelId == Channels.Facebook)
{
Activity replyToConversation = _flowService.ConvertMarkdownUrlToFacebookUrl(turnContext.Activity, response.Answer);
await turnContext.SendActivityAsync(replyToConversation, cancellationToken: cancellationToken);
}
public Activity ConvertMarkdownUrlToFacebookUrl(Activity message, string queryResponse)
{
var buttons = getButtons(queryResponse, out string result);
Activity replyToConversation = message.CreateReply();
replyToConversation.Attachments = new List<Attachment>();
List<CardAction> actions = new List<CardAction>();
foreach (var button in buttons)
{
actions.Add(new CardAction()
{
Title = button.Key, // text hyperlink
Type = ActionTypes.OpenUrl,
Value = button.Value // url
});
}
Attachment attachment = new HeroCard
{
Text = result, // your text
Buttons = actions
}.ToAttachment();
replyToConversation.Attachments.Add(attachment);
return replyToConversation;
}
You'll obtain something like this:
(sorry I had to delete the text)
Maybe it's not perfect (my first time with cards and attachments) but I hope that this will help someone 🙂
In botframework v3 I used to be able to pass any object in the entities of a message. In v4, I can pass only object with the "type" string member. At least as shown in the Bot emulator.
Why is this? Is there another way to pass custom objects? I have customers that are using the v3 way to pass objects as message metadata
While much has changed in V4, there is no significant difference between V3 and V4 when it comes to activities. You can still use entities to pass metadata in activities. Other ways to include metadata in activities are:
ChannelData
Properties
Value
Consider the following code:
private async Task TestEntitiesAsync(ITurnContext tc,
CancellationToken cancellationToken)
{
var reply = tc.Activity.CreateReply("reply");
var entity = new Entity("test")
{
Properties = JObject.FromObject(new { Foo = "Entity", Bar = 1 }),
};
reply.Entities = new[] { entity };
reply.ChannelData = new { Foo = "ChannelData", Bar = 2 };
reply.Properties = JObject.FromObject(new { Foo = "Properties", Bar = 3 });
reply.Value = new { Foo = "Value", Bar = 4 };
await tc.SendActivityAsync(reply);
}
The JSON of the activity it generates looks like this:
{
"Bar": 3,
"Foo": "Properties",
"attachments": [],
"channelData": {
"Bar": 2,
"Foo": "ChannelData"
},
"channelId": "emulator",
"conversation": {
"id": "xxxx|livechat"
},
"entities": [
{
"Bar": 1,
"Foo": "Entity",
"type": "test"
}
],
"from": {
"id": "3",
"name": "Bot",
"role": "bot"
},
"id": "xxxx",
"localTimestamp": "2018-12-26T15:33:36-08:00",
"locale": "en-us",
"recipient": {
"id": "xxxx",
"role": "user"
},
"replyToId": "xxxx",
"serviceUrl": "http://localhost:1234",
"text": "reply",
"timestamp": "2018-12-26T23:33:36.022Z",
"type": "message",
"value": {
"Bar": 4,
"Foo": "Value"
}
}
I recommend using Activity.Properties because ChannelData, Entities, and Value all have predefined uses, though they all should still serve your purposes in most cases. Remember that everything you write in C# (or whatever language you're using) is just going to be converted into JSON and sent through an HTTP message. The SDK is just providing an easy way of implementing the schema.