Using user message in retryPrompt - node.js

In a given moment, my bot asks for a number.
builder.Prompts.number(session, "Cool. What's the number?", {
retryPrompt: "I couldn't understand $%##. Could you type it again?"
});
I need the message to contain the user response instead of $%##. Is there a way to do it? I tried to use session.message.text and results.response, but these are still from the outer function because of closure.

For anyone looking for this answer: currently, there is no way to change the message inside the Prompt dialog.
I looked up the code for BotFramework for nodeThe message you send as retryPrompt is as is, without replacements.

Related

How can I save a Message in Discord with Python, in a simple variable

Hello Stackoverflow Community,
I wanted to write a Discord-Bot in Python, which should solve simple Mathquestions, like: "Whats 55+40?". The Questions are asked from another bot and the structure of the Question is everytime the same. I wrote a Calculator and it works and i just need the input from a private message(not a server). I do not need to show any code, because I dont have some and I need to start at the described situation to save the messages in a variable, so my Question is:
How can I import private messages from Discord, to save them in a normal variable, like x?
I use Sublime Text
Thanks for answers!
Looking at the comments of the question it is clear that you don't have any code for a bot yet. Look at this quickstart guide to set up a bot. Once set up, all messages typed to the bot (also DM messages) will trigger the on_message event. You can then save the contents of the message into a variable like so
#client.event
async def on_message(message):
messageContent = message.content
i assume what you mean is waiting for a user to reply to a certain message from the bot, you can get your bot to private message someone by doing something like this:
user = ctx.author
await user.send("Hello, world!")
now, for your bot waiting for a reply for your user, in your code, you will need a check just to make sure only the bot is waiting for a message from the specific person (even in dms) by creating a check function:
def check(m):
return m.author.id == ctx.author.id
then after using user.send to send a message, or an embed, add
message = await bot.wait_for('message', check=check, timeout=120)
which means the bot waits until the user sends their answer (waits 120 seconds in this example)
then, to get the content of the message you just want to do make a variable called content or answer and set it to message.content ( content = message.content )

How to add reaction to a specific message using the ID? (discord.py)

I've been trying for hours a command that react to a message using the ID.
If someone writes !react (the message ID) the bot reacts to the message.
Can someone help me? I have no clue how to do this.
Use a converter to get the discord.Message instance of the message:
#client.command()
async def react(ctx, message: discord.Message):
...
Then use Message.add_reaction to add a reaction to it, which I'm sure you can figure out by yourself.
Keep in mind that in case the message ID is invalid, can't be found, or is not in the same channel as where the command gets called, the converter will fail & throw you an exception. If you pass in the message's URL instead of the ID, Discord will be able to figure out what channel the message was sent in so you can call the command from wherever you want.
You can get a message's URL by selecting Copy Message Link, which might be better for your users as getting the id requires Developer Mode to be on, which most people don't have enabled. The MessageConverter mentioned in the beginning can parse both id's and URL's so you don't have to worry about that part.

Preventing a discord bot from executing a command in a user prompt

I need some help/suggestion to prevent a discord bot from executing a command in a user prompt.
My bot currently has a feature that prompts the user a question, and it'll add whatever the user's answer is to the database. The problem that I'm trying to solve is, currently the user's able to enter a bot command as an answer, and the bot would both execute that command and take that as an answer to add to the database.
A very quick example to show how problematic this can get:
User: ?question
Bot: Cats or Dogs?
User: ?question
Bot: "?question" have been added to the database
Bot: Cats or Dogs?
I don't have a problem with the bot adding the command to the database, because that's what the user entered (it might be relevant for the user to enter a bot command there), but I don't want the bot to execute that command.
Right now I have 2 vague ideas to solve this (I don't know whether or not any of this will be valid):
I need to turn the user's answer into an "answer" type variable where the bot can't use it to search for commands, but can still use it to upload to the database and fetch from it and display in a list of answers. Although I don't know if this can be executed before the bot starts to search for the command.
I need to somehow change how this system of question & answer works.
Note: Currently my bot detects a command by slicing the first bit of the user's message .slice(config.prefix.length)
Any help or suggestion will be much appreciated.
Thanks in advance!
Here's some answers to your question:
The bot takes in a command as an answer.
If you ever change your mind, you can disallow this by simply allowing only a few selected responses ("cat" or "dog") or disallowing commands that start with a ?.
The command is executed if a command was used as an answer.
This is because you check if the message is a command down the line, somewhere in your code. Not only does the bot recognize the user's message as a valid answer, but it also recognizes that it fulfills the prefix you set and thus it runs the command.If you have a flag that indicates that the user's next response is an answer to the Q&A question, then you can check if that flag is active before executing the command. For example:
// Assume that the user's ID is in this array after they
// requested to answer a Q&A question.
var usersAwaitingResponse = [];
...
client.on("message", function(message) {
if (usersAwaitingResponse.includes(message.author.id)) {
// take in the answer and then end the function by calling "return;"
} else {
// check if the message was a command and act accordingly
}
});
Prefix Checking
Lastly, I recommend that you check if a message is a command by using .startsWith(config.prefix) on the message text. If you want the user to only input allowed characters after the prefix, then you can use a regular expression. Either method saves time and memory rather than slicing the string. An example of those can be seen below:
// using "startsWith"
function checkIfCommand(message) {
return message.content.startsWith(config.prefix);
}
// using a regular expression
function checkIfCommand(message) {
/**
* If all the matches are fulfilled, the test passes:
*
* ^ - The match should be at the beginning of the string.
* ${config.prefix} - The prefix (interpolated into the string).
* [A-Z0-9]+ - match as much characters that are A to Z or 0 to 9
* \s? - Match a whitespace character (if there is one)
* "gi" - global, case insensitive
**/
return new RegExp(`^${config.prefix}[A-Z]+\s?`, "gi").test(message.content);
}

How to mention the author of a message in another message

I am using repl.it to develop a bot. I am trying to make a command that makes the bot behave like this:
Someone: !slap #someoneelse
Bot: #Someone slapped #someoneelse
How can I get the bot to mention #someone without using ID? Multiple people will use the command and I can't just use ID since it will only work with one person. I haven't found anything that helped me, and the documentation was no help either. Hopefully, I can get help! Thank you.
Users and members have a .toString() method that is automatically called every time they are concatenated with a string: that means that if you type "Hey " + message.author you will get "Hey #author"
That's how I would do the command:
// First store the mentioned user (it will be undefiend if there's none, check that)
let mentionedUser = message.mentions.users.first();
// Reply by directly putting the User objects in the string:
message.channel.send(`${message.author} slapped ${mentionedUser}`);

Update a bot message after responding to a slack dialog

I'm having some issues to update an interactive message after responding to a slack dialog. I'm using botkit on a node.js server.
Here is my workflow:
User trigger an interactive message via a slash command
User click a button on that message
A dialog pops up, user fill the form and validate
Something is done on the server side
The first message should update
Now, here is the logic I'm using:
User trigger an interactive message via a slash command
Nothing fancy, I use:
controller.on('slash_command', function (bot, message)
Then I parse the command, and send the appropriate message, with the appropriate attachments (buttons)
User click a button on that message
Same, I use the event sent by botkit:
controller.on('interactive_message_callback', function (bot, message)
Then I create a dialog:
var dialog = bot.createDialog(
'Which book?',
JSON.stringify(callback),
'Ok'
)
Here I'm doing something really (really) dirty, and should not be done. But that's the only way I found to update the initial message after the dialog is filled.
The callback_id actually contains an object, with the response_urlof the initial message (and something to identify the form).
A dialog pops up, user fill the form and validate
Something is done on the server side
Here, I use once more the event provided by botkit:
controller.on('dialog_submission', function (bot, message)
then I parse the message.submission.callback_id and detect the response_url. With this, I can create an object I call originalMessage.
The first message should update
At the moment I use :
bot.replyInteractive(originalMessage, 'DONE, everything is saved.');
with originalMessagecontaining the response_url of the first message.
It does work. The first message is being replaced by the new one.
But I'm really not happy with that solution, and was wondering if I was missing something somewhere. I've seen couple apps having that type of workflow, so there must be a way.
Thank you for your help :)
I wrote to Slack to ask about this situation and got a great suggestion from Mark P:
Use the state dialog field to pass the original response_url to the dialog. Then when you receive the dialog data, you can use state instead of response_url.
I just tried it and it worked great. No need to store any state on your own server.
I don't know how that would work exactly with Node and botkit, since that's not what I use.
To flesh this out a bit more:
Someone clicks a button and Slack POSTs about that interaction to your configured "Request URL".
From Slack's payload, get the "response_url" value.
When you call dialog.open in the Slack API, pass along this response_url as the "state" value.
When the dialog is submitted, Slack again POSTs to your "Request URL".
From Slack's payload, get the "state" value and use it as a response_url.
Profit!
This only works if you hold the original message object somewhere on your server for future reference.
So on creating the interactive dialog store it somewhere and add a reference. I use uuids.
let newId = uuid();
messageStore[newId] = message;
var dialog = bot.createDialog(
'My Dialog',
'idPrefix_' + newId,
'Submit'
).addText('Sample Input', 'input', '');
bot.replyWithDialog(message, dialog.asObject());
Then once you get your interactive dialog response back disassemble the prefix and the uuid and get your original message object back from the servers memory. Then use ´replayInteractive` there.
controller.on('dialog_submission', function handler(bot, message) {
if (message.callback_id.indexOf('idPrefix') === 0) {
let id = message.callback_id.substr('idPrefix_'.length);
bot.dialogOk();
let originalMessage = messageStore[id];
bot.replyInteractive(originalMessage, {
text: 'replacing the original message with this.'
});
}
});
Be careful that you do not create a memory leak here. You have to find a way to clean up your messageStore over time.

Resources