I have follow-up intents same here
Appointment
---Get Fullname
---Get Number Phone
---Get Address
---Yes
---No
Get Fullname has $fullname parameter
Get Number Phone has $phone
Get Address has $address
From Get Address, the response is a confirmed button.
In Yes intent, I design getting 'Yes' then switch to fulfillment. I can print information by using #GetFullName-followup.fullname, #GetNumberPhone-followup.phone, #GetAddress-followup.address in Yes intent.
function saveDataHandler(agent){
const{
fullname, phone, address
} = agent.parameters;
const data = [{
Name: fullname,
Phone: phone,
Address: address
}];
axios.post('googlesheets', data);
}
let intentMap = new Map();
intentMap.set('Yes', saveDataHandler);
It doesn't save data into google sheets.
I try given value directly, it also isn't working
function saveDataHandler(agent){
const{
fullname, phone, address
} = agent.parameters;
const data = [{
Name: "Bee",
Phone: "000000",
Address: "NN"
}];
axios.post('googlesheets', data);
}
let intentMap = new Map();
intentMap.set('Yes', saveDataHandler);
Related
I am working on an API for which the requirement from UI is based on the value of the search field I shall receive the filtered results. There are many search fields on UI.
Example code -
async getRoomsByMember(active: boolean, email: string): Promise<any[]> {
return await getRepository(Room)
.createQueryBuilder('room')
.innerJoinAndSelect('room.member', 'member')
.where("room.active = :active", {active: active})
.andWhere("member.email = :email", { email: email })
.getMany();
}
I shall be able to filter room members dynamically if values entered by a user on filter fields like - member phone number, city, state, country, and zip.
You're almost there :-)
You can try something like this:
async getRoomsByMember(active: boolean, email: string): Promise<any[]> {
const query = getRepository(Room)
.createQueryBuilder('room')
.innerJoinAndSelect('room.member', 'member')
.where("room.active = :active", {active: active});
// Keep adding your other fields like member phone number, city, state, country, and zip, like below
if(email) {
query.andWhere("member.email = :email", { email: email })
}
return query.getMany();
}
TLDR; (title) How to assign a default value to a required parameter via Dialoflow Fulfillment?
Long question:
I have these 2 required parameters. user_id and user_pin.
I utilized Fulfillment webhook call for slot-filling and everything seems to work well except this behavior:
After an API call to the database to verify if user_id and user_pin matches and they do not match, Dialogflow chatbot responds with "Incorrect user pin please provide the correct pin."
User then provides another user_pin but Dialogflow triggers the slot-filling and asks for the user_id again. - "Please provide a user ID".
I don't want it to ask for the user_id again. So to fix that, after an incorrect user_pin is provided, I created a context: "incorrectPinContext" with parameters {user_pin:user_pin}. I then set the default values to:
user_id = #incorrectPinContext.user_id
This fixes the problem as Dialogflow is smart enough to know if user_id is already provided or not and no longer asks again for user_id. But all of the default value assignment I've done was only through the console / UX of Dialogflow not in fulfillment. I've browsed through Google's documentations but cant seem a reference on how to do that.
So that brings me to the question: How to assign a default value to a required parameter via Dialoflow Fulfillment?
Short answer, use a structure like
agent.setContext({
name: 'question2',
lifespan: 5,
parameters: {'name': name,'id': id},
});
const context = agent.getContext('question2');
const name = context.parameters.name
const id = context.parameters.id;
Long answer, let me show it to you with an example.
Assume you have a conversation where you are trying to extract the name and the id. This is done to mimic your two parameters required.
Then, the fulfillment structure has to be like
function welcome(agent){
agent.add(`Can you tell me your name and id?`);
agent.setContext({
name: 'question',
lifespan: 3,
});
}
function answers(agent){
agent.getContext('question');
const name = agent.parameters['given-name'];
const id = agent.parameters.id;
if (name && id) {
agent.add(`So your name is ${name} and your id ${id}`);
} else if (name) {
agent.add(`Hello ${name}, what was your id?`);
} else if (id) {
agent.add(`So your id is ${id} but what is your name?`);
} else {
agent.add(`Can you tell me your name and id?`);
}
agent.setContext({
name: 'question2',
lifespan: 5,
parameters: {'name': name,'cid': id},
});
}
function answers2(agent){
const cont = agent.getContext('question2');
const cname = cont.parameters.name;
const cid = cont.parameters.cid;
const nname = agent.parameters['given-name'];
const nid = agent.parameters.id;
if (cname){
if (cid){
agent.add(`So your name is ${cname} and your id ${cid}`);
} else if (nid){
agent.add(`So your name is ${cname} and your id ${nid}`);
} else {
agent.add(`Sorry still I do not know what is your id`);
}
} else if (cid){
if (cname){
agent.add(`So your name is ${cname} and your id ${cid}`);
} else if (nname){
agent.add(`So your name is ${nname} and your id ${cid}`);
} else {
agent.add(`Sorry still I do not know what is your name`);
}
} else {
agent.add(`I still need both your name and your id`);
}
}
Then, you can perform the following conversation:
Hello!-> Can you tell me your name and id?
Sure, my name is Alan -> Hello Alan, what was your id?
77678 -> So your name is Alan and your id 77678
You will need to modify the functions and the structure to fit your needs but I think this example is illustrative of how to pass values using context in fulfillment.
Notice that if you use the same variable name in two contexts, for example id, it would get changed with the new value and thus would not be remembered. That is why I used "cid".
I need a separate input for CVC and Expiry, so I have created 3 Stripe Elements:
let elements = stripe.elements();
let cardNumber = elements.create('cardNumber');
cardNumber.mount('#card-number');
let cardExpiry = elements.create('cardExpiry');
cardExpiry.mount('#card-expiry');
let cardCvc = elements.create('cardCvc');
cardCvc.mount('#card-cvc');
...
Stripe Docs only mention about how to pass card or cardNumber Element to PaymentMethod, but how do I pass cardExpiry and cardCvc?
function paymentMethod() {
return stripe.createPaymentMethod({
type: 'card',
card: cardNumber,
billing_details: {
name: userName,
email: userEmail,
},
}).then(function(result) {
// code
});
}
Stripe Docs only mention that
Stripe.js methods automatically use all the different elements on your page under the hood, so you don't need to pass CVC and Expiry elements manually, createPaymentMethod will do that automatically under the hood for you.
Does it consider security problem when I pass req.body directly to the database (I use mongoose and nodejs)?
Let's say I have a person schema (name: string, age: number) and in req.body, someone tries to add an extra field to it. Do I need to extract only field that I need before passing it to db
const {name, age} = req.body
const person = new Person({name, age})
person.save()...
OR this is ok because mongoose already take care of that
const person = new Person(req.body)
person.save()...
Note: I am asking about extra fields, not about whether or not we should santinize the field that declared in schema
No, it's not a security problem in itself.
And that's not related with Mongoose either. That's pure JavaScript.
You are using destructuring assignment on the req.body params, so you are extracting exactly specified arguments.
const body = { name: 'bob', age: 12, malicious_entry: "rm -rf" };
let {name, age} = body;
console.log(name, age, malicious_entry) // ReferenceError: malicious_entry is not defined
And if you pass it to a constructor:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let {name, age, malicious_entry} = body;
let person = new Person(name, age, malicious_entry);
console.log(person) // Person { name: 'bob', age: 12 }
I let you choose if you want to record an internet request directly in your database without checking it, but clearly extra parameters are not the problem.
I am having issue in sending mails to multiple recipients.
My script is
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('<<username>>', '<<password>>');
sendgrid.send({
to: 'nabababa#gmail.com',
from: 'sengupta.nabarun#gmail.com',
bcc: ["sengupta.nabarun#gmail.com","sengupta_nabarun#rediffmail.com"],
I have two questions here
Can I have an array of recipients in to list?
How can I get an array of recipients in bcc list?
Solutions related to above two queries will be indeed helpful
Thanks
Nabarun
You may use an array of recipients in both the to and bcc fields.
For example:
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('{{sendgrid username}}', '{{sendgrid password}}');
sendgrid.send({
to: ['one#example.com', 'two#example.com'],
from: 'nick#sendgrid.com',
bcc: ['three#example.com', 'four#example.com'],
subject: 'This is a demonstration of SendGrid sending email to mulitple recipients.',
html: '<img src="http://3.bp.blogspot.com/-P6jNF5dU_UI/TTgpp3K4vSI/AAAAAAAAD2I/V4JC33e6sPM/s1600/happy2.jpg" style="width: 100%" />'
});
If this isn't working for you and Node isn't spitting out any errors, check to see if the emails are being sent, by logging into SendGrid's website and looking at the Email Activity Log.
One thing I came across while testing your code sample is if you're sending the to and bcc to the same gmail address, gmail will combine it all into one email (so it appears it didn't work). Make sure when testing you're sending email to entirely different accounts.
If you need some email accounts to test with Guerrilla Mail is an excellent option for creating temporary test accounts.
This is the solution that I ended up with and thought it was more straightforward and could be helpful for folks.
Note the difference in the shape of the personalizations object.
Recipients can see each other:
const sgMail = require('#sendgrid/mail')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
// Declare the content we'll use for the email
const FROM_EMAIL = 'example#example.io' // <-- Replace with your email
const subject = 'Test Email Subject'
const body = '<p>Hello HTML world!</p>'
const recipients = ['alice#example.com', 'bob#example.com'] // <-- Add your email(s) here to test
// Create the personalizations object that will be passed to our message object
let personalizations = [{
to: [],
subject
}]
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[0].to[index] = { email: recipients[index] }
}
const msg = {
personalizations,
from: FROM_EMAIL,
html: body,
}
// Log to see what our message object looks like
console.log(msg)
// Send the email, if success log it, else log the error message
sgMail.send(msg)
.then(() => console.log('Mail sent successfully'))
.catch(error => console.error(error.toString()))
Personalizations Object:
{
personalizations: [{
to: [
{email: "alice#example.com"},
{email: "bob#example.com"},
],
subject: "Test Email Subject"
}]
}
Recipients can not see each other:
// Create the personalizations object that will be passed to our message object
personalizations = []
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[index] = { to: recipients[index], subject}
}
Personalizations Object:
{
personalizations: [
{
to: "alice#example.com",
subject: "Test Email Subject"
},
{
to: "bob#example.com",
subject: "Test Email Subject"
}
]
}
I created a RunKit with the full solution and where you can test it out.
For Sendgrid's v3 API, I found their "kitchen sink" example helpful. Here is a relevant bit from it:
var helper = require('sendgrid').mail
mail = new helper.Mail()
email = new helper.Email("test#example.com", "Example User")
mail.setFrom(email)
mail.setSubject("Hello World from the SendGrid Node.js Library")
personalization = new helper.Personalization()
email = new helper.Email("test1#example.com", "Example User")
personalization.addTo(email)
email = new helper.Email("test2#example.com", "Example User")
personalization.addTo(email)
// ...
mail.addPersonalization(personalization)
The new sendgrid-nodejs update has scrapped previous implementation methods and therefore the accepted answer wont help you now.
So... just an update in case anyone lands to this thread with specific search result.
to: [
{
email: 'email1#email.com',
},
{
email: 'email2#email.com',
},
],
A solution for TypeScript (written in ts version 3.4.3 and sendGrid 7.1.1) where you don't want recipients to be able to see each other.
import * as sendGrid from '#sendgrid/mail'
type UserEmail = {
to: string
subject: string
}
// Add as many recipients as you want
recipients = ['email1#global.com', 'email2#gmail.com']
const personalizations: UserEmail[] = recipients.map(admin => ({
to: admin,
subject: 'Inject Subject Here',
}))
try {
await sendGrid.send({
from, // Inject
personalizations,
html, // Inject
})
} catch (err) {
console.log(err)
}
const personalizations looks like this
[{ to: 'email1#global.com',
subject: 'Inject Subject Here' },
{ to: 'email2#global.com',
subject: 'Inject Subject Here' }]