Passing information from inquirer prompt to another function? Node.js - javascript

Just getting back to coding and doing some practice on some fun code I came across from a friend.
I am using inquirer to ask the user what attack they would like to use. I then want to pass that information into another function.
I am having trouble finding a way to take the option from the array that the user chooses, and use it outside of the attackPrompt function.
Almost anything helps. Thanks.
let attacks = [
"Slap",
"Bite",
"Kick",
]
function attackPrompt() {
let attackChoice = [{
name:"attack",
type:"list",
message:"Choose your attack.",
choices: attacks
}]
inquirer.prompt(attackChoice).then((answer) => {
attackChosen(attackOption);
console.log("MY STRING HERE", answer.attack)
//trying to make a function where I can pass the information to another maybe?
function attackChosen() {
let optionFromChooseAttack = answer
// console.log("I PUT THIS STRING HERE", optionFromChooseAttack)
}
})
}
attackPrompt();

Related

Extract variables from json string

Context :
I'm making a Discord bot using the discord.js library and MongoDB (with mongoose). I created a script that can construct messages from data stored in my MongoDB database. For exemple, if an user on my Discord server type "!hello", it will query my database to construct a reply like "Hello to you!".
I store my reply message data in an document like this :
{
"command": "!hello",
"content": "Hello to you!"
}
(I voluntary omitted some properties here that are useless in the context of my question)
And retrieve it in my code with something like :
let retrievedReply;
await mongo().then(async mongoose => {
try {
let query = {command: message.content};
retrievedReply = await replySchema.findOne(query);
} finally {
mongoose.connection.close();
}
});
message.reply(retrievedReply.content);
My issue :
Now, imagine I want it to respond "Hello username!".
If I didn't construct my reply using data from mongo I could simply do something like :
message.reply(`Hello ${message.member.nickname}!`);
or
message.reply("Hello " + message.member.nickname + "!");
So, in other words, using backticks and ${} syntax or (but I like it less), splitting my string and concatenate my property value like the second example.
The thing is, we can't store a string inside backticks in json format (used by MongoDB). So even if I build my document like so :
{
"command": "hello",
"content": "Hello ${message.member.nickname}!"
}
${message.member.nickname} would not be interpreted like a property value but just like a simple string.
The 1000$ question :
How can I use this property inside my code? I thought about extracting it using regex but it does not change the fact that it will still be a string. Is there a way to "convert" from a string to an usable variable?
EDIT
Since Brettski asked me (rightfully), here is an example of what I want :
message.member.send(`Hello ${message.member}!`);
This message.member property here represent a member object of a Discord guild. It contains a lot of things like its permissions on the guild, its roles, etc.
When we use a member object into a message, Discord will make a mention of the member like bellow.
It works the same with other properties like channels for example. Users can then click on those to see informations about the member or to go directly to the channel, etc. I want to be able to use this.
That is correct you will not be able to store a string literal in Mongo or other way.
One though I had is to put a token in your string and then do a replace on it in message.reply() or before it.
example:
const helloCommand = {
"command": "hello",
"content": "Hello ~~membernickname~~!"
};
In this example the token to replace is ~~membernickname~~
You can use something like this to do the replace:
const command = JSON.parse(helloCommand)
message.member.send(command.content.replace('~~membernickname~~', message.member));
The resulting string being sent to the send() command is the same. So if the nickname is #brettski, the string 'Hello #brettski' will be sent to the send() command.
In your example:
message.reply(`Hello ${message.member.nickname}!`);
the part:
`Hello ${message.member.nickname}!`
is a string literal (template literals). What the function message.reply() ends up getting is 'Hello Nickname' a string. So the replace should work. As a test you can hard code the string used in message.reply() to a known nickname and it should provide the results you expect.
Ok so, #Brettski put me on the right track with the fact that I can use users' or channels' IDs directly as strings within the message and between specific tags.
To reuse the example in my question, I can use this syntax to mention an user :
"<#idOfTheUser>"
What I did is if I want to mention the author of the command in my reply, I put the text in my mongoDB document as so :
const helloCommand = {
"command": "hello",
"content": "Hello $member$!"
};
Then, in my code, I can simply use :
message.reply((retrieveReply.content).replace(/\$member\$/g, `<#${message.member.id}>`))
Of course, I wanted to use more properties so I did a function like :
const messageContentReplace = function(content) {
const replaceableStrings = {
"$member$": `<#${message.member.id}>`,
"$memberName$": message.member.displayName,
"$guild$": message.guild.name
}
return content.replace(/(\$member\$)|(\$memberName\$)|(\$guild\$)/g, match => {
return replaceableStrings[match];
});
(in reality, I did something more complexe because I use an embed message as my response with multiple fields etc... See here about embeds)

Only allow certain fields (Firestore Rules)

Im trying to create a rule that only allows certain fields to be updated within my firestore rules, so I thought about doing a function like so:
function checkFieldsSent() {
for(field in request.resource.data) {
if (!(field in ['userRole', 'userName', 'messageType', 'userMessage', 'userHonourLevel', 'userAvatar', 'userChatPosted', 'userLevel', 'userChatMessage'])) { return false }
}
return true
}
of course as you can imagine, firestore moans about the use of "FOR" and "Return" within that function.
Does anyone know a solution? So if the request comes through with fields that ARE NOT ALLOWED to be updated it disallows the update.
Kind Regards,
Josh
Loops are not allowed in the rules. But there is a new data type available since February that gives a nice solution: Map.Diff.
function checkFieldsSent() {
let forbiddenfields = ['userRole', 'userName', 'messageType', 'userMessage', 'userHonourLevel', 'userAvatar', 'userChatPosted', 'userLevel', 'userChatMessage'];
return !request.resource.data.diff(resource.data).affectedKeys().hasAny(forbiddenfields);
}
More details here

Add confirm prompt in another language

How to add the confirm Prompt and Good bye message in another language based on user choice of language. Lets say I want to add a spanish version thats says goodbye
.cancelAction(
"cancelRequest", "Thank you for reaching out, Good bye!",
{
matches: /^nevermind$|^cancel$|^cancel.*request/i,
confirmPrompt: "This will cancel your request. Are you sure?"
}
);
You can do this using a variable which value is set depending on the language. This variable can then be used to get the corresponding text from an object.
For example:
var language = "spanish";
var cancelTextFromLang = {
spanish: "Gracias por comunicarte, ¡Adiós!",
english: "Thank you for reaching out, Good bye!",
french: "Merci d'avoir tendu la main, au revoir!"
};
console.log(cancelTextFromLang[language])
You can apply this to your given code like so:
var language = "spanish";
var cancelTextFromLang = {
spanish: "Gracias por comunicarte, ¡Adiós!",
english: "Thank you for reaching out, Good bye!",
french: "Merci d'avoir tendu la main, au revoir!"
};
.cancelAction(
"cancelRequest", cancelTextFromLang[language],
{
matches: /^nevermind$|^cancel$|^cancel.*request/i,
confirmPrompt: "This will cancel your request. Are you sure?"
}
);
Im using session.userData.languagePreference and Im thinking to add an if statement inside the cancelAction but the syntax is wrong, I cant put the if statement there :/
.cancelAction(
if ( session.userData.languagePreference = 0;) {
"cancelRequest", "Thank you for reaching out, Good bye!",
{
matches: /^nevermind$|^cancel$|^cancel.*request/i,
confirmPrompt: "This will cancel your request. Are you sure?"
}
);
The Bot Framework supports localization. You can read about how to do this in Node here. This page will explain how to determine the language for the bot user either via prompting the user or automatically. it also describes how to add the language strings for your prompts.
They key to bot localization is the session.preferredLocal() method. This method saves and gets the user specific locale preference.
The easiest method to determine the language locale and set it is to prompt the user. Here's a Node example
bot.dialog('/localePicker', [
function (session) {
// Prompt the user to select their preferred locale
builder.Prompts.choice(session, "What's your preferred language?", 'English|Español');
},
function (session, results) {
// Update preferred locale
var locale;
switch (results.response.entity) {
case 'English':
locale = 'en';
break;
case 'Español':
locale = 'es';
break;
}
session.preferredLocale(locale, function (err) {
if (!err) {
// Locale files loaded
session.endDialog(`Your preferred language is now ${results.response.entity}`);
} else {
// Problem loading the selected locale
session.error(err);
}
});
}
]);
The first part of this code prompts the user for their preferred language and gives them English and Spanish as the two option available. Based on the user response, the locale code is then set by calling session.preferredLocale().
In order to make use of the user's preferred locale, you will need a corresponding localization prompt file. These files will contain the various bot prompts in the corresponding language. You will need one file per language you intend on supporting.
Normally, these files will be in ./locale/{language}/index.json where {language} is the language code, (ex 'en' or'es'). The files are json and will look like this:
for English
{
"greeting": ["Hello!", "Hi there"]
}
and for Spanish
{
"greeting": ["Hola!", "Hola"]
}
Here is an example of how you code would look
var bot = new builder.UniversalBot(connector, [
function (session) {
session.send("greeting");
session.beginDialog('/localePicker');
},
function (session) {
builder.Prompts.text(session, "text_prompt");
}
]);
Behind the scenes, what's basically happening,the index.json file returned by session.preferredLocale() is searched for the prompt, if it finds one, it returns that otherwise it will return the prompt set for the default locale.

Algolia Instant Search Firebase Cloud Function - how to get the other value?

I don't have much idea about JavaScript, so I used Algolia's Instant Search for Firebase Github Repository to build my own function.
My function:
exports.indexentry = functions.database.ref('/posts/{postid}/text').onWrite(event => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
const firebaseObject = {
text: event.data.val(),
timestamp: event.data.val(),
objectID: event.params.postid
};
In Algolia indices, with timestamp as the key, I get the same value as in text field, but in Firebase backend timestamp is different. How to fix this?
I tried different statements to get timestamp value but couldn't.
Edit
Expected Outcome:
{
text: "random rext",
timestamp: "time stamp string",
author: "author name",
object ID: "object ID"
}
Actual Outcome
{
text: "entered text",
object ID: "object ID"
}
I'm not real clear about your goal. Event has a timestamp property. Have you tried:
const firebaseObject = {
text: event.data.val(),
timestamp: event.timestamp, // <= CHANGED
objectID: event.params.postid
};
If you want a long instead of string, use Date.parse(event.timestamp)
EDIT 2: Answer can be found here.
Original Answer: What Bob Snyder said about the timestamp event is correct.
There may be other fields as well, for example, author_name that we may need to index, is there a generalized way to do that or do I write separate functions for every field?
If you want a general way to add all fields, I think what you are looking for can be found here. This should give you the right guidance to get what you want, i.e save your whole object into the Algolia index.
EDIT:
index.saveObject(firebaseObject, function(err, content) {
if (err) {
throw err;
}
console.log('Firebase object indexed in Algolia', firebaseObject.objectID);
});
event.data.val() returns the entire firebase snapshot. If you want a specific value in your data you add it after .val() for example if every post has an author stored in your firebase database under they key "author" you can get this value using var postAuthor = event.data.val().author
I've included some samples from my code for those interested. A sample post looks like this:
Then inside my cloud functions I can access data like this:
const postToCopy = event.data.val(); // entire post
const table = event.data.val().group;
const category = event.data.val().category;
const region = event.data.val().region;
const postKey = event.data.val().postID;

How do I add an action to watson conversation response?

I've created intent, entity and dialog without a problem. But right now I'm trying to make it so when the user send "goodbye", the application would close. According to the doc, I'll have to name an action that goes along with an intent. How do I do that? Is it through code or through the conversation workspace platform?
You can use context variables or action variables for that.
How to use context variables? Add in your Advance response the "context" and the values, check my example.
I've used the conversation simple for that.
In your Watson Developer Cloud - IBM Bluemix - Watson Conversation, add in the Advanced response this JSON example, Assuming it is in this conversation node that your application will do something:
{
"context": {
"verified": true;
},
"output": {
"text": {
"values": [
"Please wait and I'll verified your request."
],
"selection_policy": "sequential"
}
}
}
Example (app.js):
function updateMessage(input, data, req, res) {
if (data.context.verified === true){
searchRequest(data, req, res);
} else if (data.output && data.output.text) {
return res.json(data);
}
return data;
}
You can use the data for sending something within conversation flow.
function searchRequest(data, req, res){
// something to do and return value
var sendRequest = "Thanks for wait, the request is" + valueRequest;
data.output.text[0] = sendRequest;
return data;
}
EDIT:
You can add one JSON object like "action", and your code will recognize this variable, with the same example that #Mikko said. And you can check this with:
data.output.action === 'close'
See more about Context variables.
See more about Building a dialog.
You need to be careful with context variables as your next dialog node may or may not update them. Another option is to add a custom variable in the output. This is the solution used in conversation-discovery samples available in the GitHub.
"output": {
"text": {
"values": [
"Goodbye..."
],
"selection_policy": "sequential"
},
"action": "close"
}
Please note that this will cause a warning when closing the JSON editor.

Categories

Resources