How to check contents of message without including User's name in contents - node.js

Ive got a command im testing that enables the Bot to send me a message when a specific string is passed into a Channel.
My command works fine, but the bot seems to also include the user's name into the contents as well.
I found this out by testing with my name as the string the bot is running an if statement for, and found out that even typing just Hi, or any other message triggers the if statement as my name 'Jerseyetr" is included in the contents of the message.
if (message.content.includes('jersey') || ('jerseyetr')) {
try{
console.log('it worked!');
//jersey.send('testing!');
//client.users.get("xxxxxx").send("test");
return;
//guild.member
}
catch (err){
console.log(err);
console.log('it did NOT work. Sad face');
}
}
What would be the proper way to filter out the User's name?

The problem here is that you always enter in the if, and never in the else (if there's one).
Why? Because of your condition. The OR condition || will test first the message.content.includes('jersey'). If it's true it will enter in the if, if it's false it will test the second condition. But your second condition is always true, because the string 'jerseyetr' is not empty and is considered true by Javascritps.
This page list all the things that are considered falsy. All the other value are considered true.
I guess you wanted to do this:
if (message.content.includes('jersey') || message.content.includes('jerseyetr')) {
...
}
However, the second expression isn't needed because jersey is contained in jerseyetr, so if the message contains jerseyetr, it will also contains jersey.
You'll see that Discord doesn't includes the username in the message.content but only the text of the message
Side note: if you want to test something like this in your message, you can maybe use a regexp:
/jersey/.test(message.content)

Related

Alexa voice with Jovo Framework: Is this possible to get IntentName by utterance? How can I decide which intent to jump to based on user utterance?

I have built an Alexa skill with the following flow:
LAUNCH -> AccountLinkingIntent -> CampaignIntent
In AccountLinkingIntent, presently I am routing to CampaignIntent if Account is already linked.
Up to this everything is working fine. Now I have to add another Intent ActiveContactIntent so that the flow becomes:
LAUNCH -> AccountLinkingIntent -> CampaignIntent / ActiveContactIntent
i.e, From AccountLinking I need to decide which Intent to route to.
The invocation goes like this (CampaignIntent):
Alexa, ask <invocation_name> to get my latest campaign result
OR (ActiveContactIntent)
Alexa, ask <invocation_name> who is my most active contact
Based on the utterance, I need to tell Alexa where to go. So far I have the following in AccountLinkingIntent
...
return this.toIntent("CampaignIntent");
...
But now I need to decide the same as this:
...
if( ... ) {
return this.toIntent("CampaignIntent");
} else {
return this.toIntent("ActiveContactIntent");
}
...
Is there any way to get the IntentName by the utterance so that I can check by the same such as:
...
if( intent_name_by_utterance === "CampaignIntent" ) {
return this.toIntent("CampaignIntent");
} else {
return this.toIntent("ActiveContactIntent");
}
...
Or probably, if it is possible to get intent_name_by_utterance I may also pass the value as the argument of toIntent method if it is allowed to pass a variable!
return this.toIntent(intent_name_by_utterance);
UPDATE:
I have tried the following to see whether the intent name is being returned:
LAUNCH() {
return this.toIntent("LinkAccountIntent");
},
async LinkAccountIntent() {
const intent_name = this.$request.getIntentName();
this.tell(Current intent is: ${intent_name});
},
Invoked the skill in following two fashions:
Alexa, ask <invocation-name> to give me my latest campaign results
Alexa, ask <invocation-name> who is my most active contact
give me my latest campaign results AND who is my most active contact are the utterances for respective intents.
I am using Alexa Test console for testing. In both cases, I was expecting the name of the intent (this.$request.getIntentName()), ending up with
Hmm, I don't know that one.
My intention is to call an intent by its utterance directly by waking up the skill using its invocation name.
Any suggestion?
I think you should treat both intends separately and not through the launch, because for example in the case
"Alexa, ask who is my most active contact"
Alexa skips the launch and jumps directly to resolve the intend ActiveContactIntent.
So just as you have the LAUNCH(){} function you must also have CampaignIntent(){} and ActiveContactIntent(){}.
That way you will avoid Alexa answering
Hmm, I don't know that one.
To verify that the user has already linked his account, you would have to enter a code like the one below:
if (!this.$request.getAccessToken()) {
this.$alexaSkill.showAccountLinkingCard();
this.tell('Please link you Account');
} else {
//code for your respective action
}
I recommend you to check the documentation about "routing with jovo" to have a little more clarity about this topic. You can review it at the following link:
https://www.jovo.tech/docs/routing

How to remove the warning "this might be empty" from result view in bixby

I am showing few information to the user on card and structure has min(Optional) and I don't want to change that. There is possibility that it might be blank. But how to put it in condition in result-view. I tried like if(this.name) but then yellow line appears on condition and template both.
Using an if statement is the correct way.
For example, here is how a capsule I have written will handle an optional gameTitle property when displaying my Character structure.
if(exists(character.gameTitle)) {
cell-card {
slot2 {
content {
order (PrimarySecondary)
primary ("#{value(character.gameTitle)}")
}
}
}
}

Pokemon Evolutions package doesn't get chains right

I am working on a pokemon bot and I am stuck in somewhere.
I want to make a command to check if a pokemon contains the second pokemon in its evolution line or not. I am using a node.js package called Evolutions.
Here is code:
if (command === 'does') {
const b = evolution.getEvolutionChain(args[0]);
const c = args[1]
if (b.includes(c)) {
msg.channel.send("True!")
} else {
msg.channel.send("False!")
};
}
The code doesn't give an error but it always sends False!.
I used in my server (where the bot is) a! is the prefix.
a!does charmander charmeleon
Everything is correct but it always sends False!, even if it needs to be True!.
Since the evolution.getEvolutionChain(args[0]); returns the values with capitalized letters it's easiest if you turn all the values (both the array of evolutions as the user given evolution) to lowercase. After that you can check if the array contains the given evolution.

dynamic prompt choices in bot-framework v4 (node.js)

I've got a prompt for an SMS bot in which the user can make multiple choices. I'm looking for a pattern for a ChoicePrompt that allows me to do this:
show multiple selections
then after the user selects and answer, re-prompt them to answer again
Remove their previous choice(s) and add an "exit" option to move on
Automatically end the step if they've selected everything.
I'd like to avoid creating a new prompt w/switch cases for each answer tier, as this pattern needs to be implemented in a lot of places...
Example:
bot: User, what do you do to relax?
Exercise
Read a book
Nothing
user: Exercise
bot: Exercise, cool. What else?
Read a book
Nothing else
user: Read a book
bot: OK, you've done everything so we're moving on!
The botframework don't have a ListPrompt that I can see, at least for v4. They do however, have Suggested Actions you can use for this!!! The Botbuilder-Samples repo has a Suggested Action sample that shows a list of three colors:
async onTurn(turnContext) {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
if (turnContext.activity.type === ActivityTypes.Message) {
const text = turnContext.activity.text;
// Create an array with the valid color options.
const validColors = ['Red', 'Blue', 'Yellow'];
// If the `text` is in the Array, a valid color was selected and send agreement.
if (validColors.includes(text)) {
await turnContext.sendActivity(`I agree, ${ text } is the best color.`);
} else {
await turnContext.sendActivity('Please select a color.');
}
// After the bot has responded send the suggested actions.
await this.sendSuggestedActions(turnContext);
} else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
await this.sendWelcomeMessage(turnContext);
} else {
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected.]`);
}
}
An option would be to programatically create the array (in the example above, it's "const validColors") and if the reply is in the list of colors, recreate the array however you want without the chosen option.

How to loop over object & return mongoDB entry for each item?

I am having difficulties looping over an object of constituency data, finding existing entries in a MongoDB and doing something with them. It always ends up being the same entry being passed to be found in the DB over and over again.
I am assuming this is a problem of scope and timing.
My code:
for (key in jsonObj) {
var newConstituent = new Constituent({
name : jsonObj[key]["Name"],
email : jsonObj[key]["Email"],
social : {
twitter: {
twitter_handle : jsonObj[key]["Twitter handle"],
twitter_id : jsonObj[key]["User id"],
timestamp : jsonObj[key]["Timestamp"]
}
}
});
console.log(jsonObj[key]["Email"]); // this is fine here!
Constituent.findOne({ email : jsonObj[key]["Email"] }, function(err, constitutents){
console.log(jsonObj[key]["Email"]); // here it's always the same record
if (err) {
console.log(err)
}
if (constitutents === 'null') {
console.log("Constituent not found. Create new entry .. ");
// console.log(newConstituent);
newConstituent.save(function (err) {
if (err) {
console.log('db save error');
}
});
} else {
console.log("Constituent already exists .. ");
}
});
}
I have a suspicion that the for loop finishes sooner than .findOne() is executing and therefor always and only gets the last item of the object passed to find.
Could someone point me into the right direction?
A couple of this.
Don't use for ... in, especially in node. You can use Object.keys() and any of the array methods at that point. for ... in can include values you don't wish to loop over unless you're using hasOwnProperty since it'll include values from the prototype chain.
The reason the email is the same is that you're just printing out your query again. jsonObj is included in the scope of your callback to findOne since you're not re-declaring it inside the findOne callback. So whatever the value of key happens to be (my guess is that it's the last one in your list) when the callback is invoked is the email you're getting. Since, in javascript, inner function scope always includes, implicitly, the scope of the surrounding context, you're just accessing the jsonObj from your enclosing scope.
To clarify about this point, your for ... in loop is synchronous -- that is the interpreter finishes running all the instructions in it before it will process any new instructions. findOne, how ever is asynchronous. Very simply, When you call it in this loop, it's not actually doing ANYTHING immediately -- the interpreter is still running your for ... in loop. It is, however, adding more tasks to the execution stack to run after it's finished your loop. So the loop is finished, AND THEN your callbacks will start to execute. Since the for ... in loop is totally finished, key is set to whatever the final value of it was. So, for example, if it's last value was foo that means EVERYTIME your callback is invoked, you will be printing out jsonObj.foo since the for ... in loop is already complete.
So it's like you asked your friend to say the letters from A to J, and you left the room to do 10 things. To do something. He totally finished going to J since that is much faster than doing 1 of the 10 things you're doing. Now every time you're done doing one of your things, you come back and say "what's the latest letter you said". The answer will ALWAYS be J. If you need to know what letter he is on for each task you either need to get him to stop counting while you're doing it or somehow get the information about what letter corresponds with the number of task that you're performing.
Having them wait is not a good idea -- it's a waste of their time. However, if you wrap your findOne in a new function where you pass in the value of key, this would work. See the updated code below.
I'm not sure about your data but findOne will return one record. You're putting it into a variable with a plural (constitutents). From reading your code I would expect back a single value here. (It might still be wrapped in an array however.)
Since you're calling findOne and assigning the results of the find operation to constituent, you should be examining that object in the console.log.
e.g.
console.log(constitutents.email); // or console.log(constitutents[0].email)
rather than
console.log(jsonObj[key]["Email"]);
(Assuming email is a property on constituants).
You might just try logging the constituants entirely to verify what you're looking for.
The reason this following code will work is that you're passing the current value of key to the function for each invocation. This means there is a local copy of that variable created for each time you call findConstituent rather than using the closure value of the variable.
var newConstituent;
function findConstituent(key){
Constituent.findOne({ email : jsonObj[key]["Email"] }, function(err, constitutents){
console.log(jsonObj[key]["Email"]); // here it's always the same record
if (err) {
console.log(err)
}
if (constitutents === 'null') {
console.log("Constituent not found. Create new entry .. ");
// console.log(newConstituent);
newConstituent.save(function (err) {
if (err) {
console.log('db save error');
}
});
} else {
console.log("Constituent already exists .. ");
}
});
}
for (key in jsonObj) {
newConstituent = new Constituent({
name : jsonObj[key]["Name"],
email : jsonObj[key]["Email"],
social : {
twitter: {
twitter_handle : jsonObj[key]["Twitter handle"],
twitter_id : jsonObj[key]["User id"],
timestamp : jsonObj[key]["Timestamp"]
}
}
});
findConstituent(key);
}

Resources