I'm trying to send custom payload from inline editor, to be displayed at DialogFlow Messenger integration. Here's my code:
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const {Payload} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function test_accordion (agent) {
const payload ={"messages": [{"richContent": [
[
{
"text": "Text to be displayed at accordion",
"type": "accordion",
"title": "Detalles:",
"image": {
"src": {
"rawUrl": "https://img2.freepng.es/20180621/ewt/kisspng-trello-logo-slack-atlassian-trello-5b2bcdc85e4d36.2783338815295973843863.jpg"
}
}
}
]
]
}]};
agent.add(new Payload(agent.UNSPECIFIED , payload, {rawPayload: true, sendAsMessage: true}));
}
let intentMap = new Map();
intentMap.set('test_accordion', test_accordion);
agent.handleRequest(intentMap);
});
And here is my packages file:
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "10"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^6.0.0",
"firebase-functions": "^2.0.2",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0",
"#google-cloud/common":"^0.25.3",
"#google-cloud/projectify":"^0.3.1",
"#google-cloud/promisify":"^0.3.1",
"#google-cloud/translate":"^2.1.2",
"#google-cloud/firestore": "^0.16.1"
}
}
I'm not able to make this work. I've been searching the net for hours and I can't find any solution.
I've also tried some solutions from stackoverflow, but they seem to be outdated, as Dialogflow keeps changing their environment.
Any help would be really appreciated.
Thanks in advance!
for me, change "dialogflow-fulfillment": "^0.5.0", to "dialogflow-fulfillment": "^0.6.1" in package.json.
And in your test_accordion function
need to return agent:
return agent;
Console Error message: v3:1 Uncaught (in promise) IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client secret of the form ${id}_secret_${secret}. You specified: .
You can see the error yourself here: https://stormy-forest-38471.herokuapp.com/
Instructions to get error: From the main page, click on Menú Diari -> Demanar -> Any of the first 3 buttons -> Select one radio button from each category and then click on Afegeix i paga -> Pagar -> 1st input: 'Random Name', 2nd input: 'Recollida a tenda - Cabrera de Mar', 4th input: '123'...
Then, according to Stripe documentation, you could fill the payment element with the following data in order to achieve a successfull test payment.
Visa Number: '4242 4242 4242 4242'
MM/AA: '04/24'
CVC: '123'
Once you press Pagar, you will get the IntegrationError I'm asking for in the console.
I am trying to deploy a React.js + Node.js + Express web using Heroku.
I have been following this guide, although I am not sure if that's what I need.
https://blog.heroku.com/deploying-react-with-zero-configuration
The web is for a restaurant. They want to sell different lunch plans. I am trying to implement the payment using Stripe. When I test the app in my localhost, everything works fine. However, when I try to deploy it, something breaks.
I guess something must be wrong with my server.js or package.json files... The main problem being that I am a complete noob at Back End...
Everything works as expected (I still have some console logs here and there for development), until I start making requests to the server.
This is my server.js
const { createServer } = require('https');
const express = require('express');
const compression = require('compression');
const morgan = require('morgan');
const path = require('path');
const normalizePort = (port) => parseInt(port, 10);
const PORT = normalizePort(process.env.PORT || 5000);
const app = express();
const dev = app.get('env') !== 'production';
if (!dev) {
app.disable('x-powered-by');
app.use(compression()); // "Will handle a few things for us... (?)"
app.use(morgan('common'));
app.use(express.static(path.join(__dirname, 'build')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
}
const server = createServer(app);
const { resolve } = require('path');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.use(express.json());
const calculateOrderAmount = (items) => {
console.log(items);
let drinksTotal = 0;
const { water, cola, colaZero, beer, lemonFanta, orangeFanta } = items.drinks;
drinksTotal += water * 100;
drinksTotal += (cola + colaZero + lemonFanta + orangeFanta) * 130;
drinksTotal += beer * 150;
let foodTotal = 0;
foodTotal += items.primerSegonCount * 895;
foodTotal += items.dosPrimersCount * 795;
foodTotal += items.platPostresCount * 695;
grandTotal = parseInt(drinksTotal + foodTotal);
console.log(grandTotal);
return grandTotal;
};
app.post('/create-payment-intent', async(req, res) => {
const { items } = req.body;
console.log(items);
// Create a PaymentIntent with the order amount and currency
const paymentIntent = await stripe.paymentIntents.create({
amount: calculateOrderAmount(items),
currency: 'eur'
});
res.send({
clientSecret: '123_secret_123' //paymentIntent.client_secret
});
});
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
server.listen(PORT, (err) => {
if (err) throw err;
console.log('Server started on port ' + PORT);
});
This is my package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"engine": {
"node": "12.16.3",
"npm": "6.14.5"
},
"dependencies": {
"#stripe/react-stripe-js": "^1.1.2",
"#stripe/stripe-js": "^1.7.0",
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"axios": "^0.19.2",
"boostrap": "^2.0.0",
"bootstrap": "^4.5.0",
"compression": "^1.7.4",
"concurrently": "^5.2.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"emailjs-com": "^2.4.1",
"express": "^4.17.1",
"morgan": "^1.10.0",
"node-sass": "^4.14.1",
"nodemon": "^2.0.4",
"react": "^16.13.1",
"react-bootstrap": "^1.0.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-scripts": "3.4.1",
"react-scroll": "^1.7.16",
"react-stripe-checkout": "^2.6.3",
"reactstrap": "^8.5.1",
"stripe": "^8.67.0",
"uuid": "^8.2.0",
"uuidv4": "^6.1.1"
},
"scripts": {
"start": "react-scripts start",
"start-dev": "nodemon server.js",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "concurrently \"npm run-script start-dev\" \"npm run-script start\"",
"heroku-postbuild": "npm install && npm run build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"]
},
"homepage": "."
}
This is the React.js file in charge of the payment
import React, { useState, useEffect } from 'react';
import { CardElement, useStripe, useElements } from '#stripe/react-stripe-js';
// Bootstrap
import { Container, Row, Col, Button, Spinner, Form } from 'react-bootstrap';
export default function CheckoutForm(props) {
const [ succeeded, setSucceeded ] = useState(false);
const [ error, setError ] = useState(null);
const [ processing, setProcessing ] = useState(false);
const [ disabled, setDisabled ] = useState(true);
const [ clientSecret, setClientSecret ] = useState('');
const stripe = useStripe();
const elements = useElements();
useEffect(() => {
console.log('inside use Effect');
// Create PaymentIntent as soon as the page loads
window
.fetch('/create-payment-intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
items: {
drinks: props.drinksOrdered,
primerSegonCount: props.primerSegonCount,
dosPrimersCount: props.dosPrimersCount,
platPostresCount: props.platPostresCount
}
})
})
.then((res) => {
console.log(res);
return res.json();
})
.then((data) => {
console.log(data.clientSecret);
console.log(data);
setClientSecret(data.clientSecret);
});
}, []);
const cardStyle = {
base: {
backgroundColor: 'white',
color: 'grey',
fontFamily: 'Montserrat, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#c6c6c6'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
},
complete: {
color: 'green',
iconColor: 'green'
}
};
const handleCardChange = async (event) => {
// Listen for changes in the CardElement
// and display any errors as the customer types their card details
setDisabled(event.empty);
setError(event.error ? event.error.message : '');
};
const handleSubmit = async (ev) => {
ev.preventDefault();
setProcessing(true);
const payload = await stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: elements.getElement(CardElement),
billing_details: {
name: ev.target.name.value
}
}
});
// Handle Error
if (payload.error) {
setError(`Payment failed ${payload.error.message}`);
setProcessing(false);
} else if (payload.paymentIntent.status === 'succeeded') {
// If payment succeeded, send eMail with details
props.sendEmail();
setSucceeded(true);
setError(null);
setTimeout(() => {
window.location.replace('https://www.cateringroser.cat');
}, 10000);
}
};
Thank you so much in advance.
Gerard
Well, as I guessed, I had to figure this one out myself. :-)
If you go back to my original post, you will be able to see the code I had for my server.js, package.json and CheckoutForm.jsx files.
The CheckoutForm.jsx was ok. Below you can see the modified versions of the code for:
server.js
const express = require('express');
const path = require('path');
const app = express();
const { resolve } = require('path');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.use(express.static(path.join(__dirname, 'build')));
app.use(express.json());
// app.use(express.json());
const calculateOrderAmount = (items) => {
let drinksTotal = 0;
const { water, cola, colaZero, beer, lemonFanta, orangeFanta } = items.drinks;
drinksTotal += water * 100;
drinksTotal += (cola + colaZero + lemonFanta + orangeFanta) * 130;
drinksTotal += beer * 150;
let foodTotal = 0;
foodTotal += items.primerSegonCount * 895;
foodTotal += items.dosPrimersCount * 795;
foodTotal += items.platPostresCount * 695;
grandTotal = parseInt(drinksTotal + foodTotal);
console.log(grandTotal);
return grandTotal;
};
app.post('/create-payment-intent', async(req, res) => {
const { items } = req.body;
// Create a PaymentIntent with the order amount and currency
const paymentIntent = await stripe.paymentIntents.create({
amount: 100, //calculateOrderAmount(items),
currency: 'eur'
});
res.send({
clientSecret: paymentIntent.client_secret
});
});
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(process.env.PORT || 8080);
package.json
{
"name": "my-app",
"version": "1.0.0",
"description": "take away restaurant app",
"private": true,
"engines": {
"node": "12.x"
},
"dependencies": {
"#stripe/react-stripe-js": "^1.1.2",
"#stripe/stripe-js": "^1.7.0",
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"boostrap": "^2.0.0",
"bootstrap": "^4.5.0",
"concurrently": "^5.2.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"emailjs-com": "^2.4.1",
"express": "^4.17.1",
"node-sass": "^4.14.1",
"nodemon": "^2.0.4",
"react": "^16.13.1",
"react-bootstrap": "^1.0.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
"react-scroll": "^1.7.16",
"react-stripe-checkout": "^2.6.3",
"reactstrap": "^8.5.1",
"stripe": "^8.67.0"
},
"scripts": {
"start": "node server.js",
"start-dev": "nodemon server.js",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "concurrently \"npm run-script start-dev\" \"npm run-script start\"",
"heroku-postbuild": "npm install && npm run build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"]
}
}
I ended up using what I knew on server.js. I deleted everything I didn't understand and kept the original code.
One of the most important things was to understand what happens when you deploy an app using node/express (or at least I think I understand).
First, I thought I needed to deploy both the Front and Back End sepparately, and then link them somehow.
What (I think) I really needed to do was to serve the Front End files from the server. In my first attempts to deploy, I was really serving them from React directly, so all I was getting was an interactive painting, in which I could navigate, but hadn't the opportunity to communicate with the server (since it was not connected).
What was the solution?
Serve the /build folder and it's files as explained in React's documentation on deployment.
Remove the "proxy": "http://localhost:5000" from package.json. Also remove "homepage":"xxx" if you had so.
Add "start": "node server.js" to your package.json. You want to open your web through node.
I also added a Procfile as recommended in Heroku's best practices for deployment with Node.js. All I have in the file is the following code: web: node server.js.
It just makes sense now. I can accept payments and communicate with my server.
As a sidenote: I didn't delete any of the Stripe specific code in my server.js, since it might help other users using Stripe to handle payments.
use secret key instead of public key in index.js in functions folder.
I am developing cloud function that use the calendar API to list the event from the calendar and parse the response to get the summary
I test my function on the dialog flow console beside and it give me the result that I want but when I integrate it with actions on google It's always go to the catch
/----- read the description for event
//----- read the description for event
function getKeyPoint (agent) {
return fetchDescription(agent.parameters.date,agent.parameters.time).then(() => {
agent.add("The key point for the requiered event is "+keyPoint);
}).catch((err) => {
console.log("Error here "+err);
agent.add(`There is no description `);
});
}
function fetchDescription (date,time){
appointmentDuration = 1;// Define the length of the appointment to be one hour.
dateTimeStart = convertParametersDate(date,time);
dateTimeEnd = addHours(dateTimeStart, appointmentDuration);
return new Promise((resolve,reject)=>{
console.log("is listing now ");
calendar.events.list({
auth: serviceAccountAuth,
calendarId: calendarId,
timeMin: dateTimeStart.toISOString(),
timeMax: dateTimeEnd.toISOString()
},(err,calenderResponse)=>{
if (err || calenderResponse.data.items.length==0){
reject(err || new Error('No event at this time '));
}else {
var calenderResponseBody = calenderResponse.data;
var events=calenderResponseBody.items;
keyPoint = events[0].description;
resolve(keyPoint);
}
});
});
}
the package :
{
"name": "DialogflowFirebaseWebhook",
"description": "Firebase Webhook dependencies for a Dialogflow agent.",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "6"
},
"scripts": {
"lint": "semistandard --fix \"**/*.js\"",
"start": "firebase deploy --only functions",
"deploy": "firebase deploy --only functions"
},
"dependencies": {
"firebase-functions": "^2.0.2",
"firebase-admin": "^5.13.1",
"googleapis": "^27.0.0",
"actions-on-google": "2.2.0",
"dialogflow-fulfillment": "^0.4.1"
}
}
I'm trying to use DeepLinks in Fulfillment Inline Editor in DialogFlow but I get error "DeepLink is not defined". The question is how to import DeepLink into project?
more info about deeplink class:
deeplink class
My index.js:
'use strict';
// Import the Dialogflow module from the Actions on Google client library.
const {dialogflow} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});
// Handle the Dialogflow intent named 'favorite color'.
// The intent collects a parameter named 'color'.
app.intent('favorite color', (conv, {color}) => {
here I have error "DeepLink is not defined"
conv.ask(new DeepLink({
destination: 'Google',
url: 'http://my.deep.link',
package: 'my.package.name',
reason: 'handle this for you',
}))
})
// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
My package.json
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "~6.0"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^4.2.1",
"firebase-functions": "^0.5.7",
"dialogflow": "^0.1.0",
"dialogflow-fulfillment": "^0.4.1"
}
}
Thanks!
I've go it! :)
The line 4 should looks like:
const {dialogflow, DeepLink} = require('actions-on-google');
I am trying to use http-hash module in order to construct an API for my application. I am using AVA as my test runner for my previous test. When I run the "npm test" command, I get this error in my console:
import { send } from 'micro'
^^^^^^
SyntaxError: Unexpected token import
I am using a linter and it doesn't send me any error. Here is my package.json, where you can see that I am using some babel plugins in order to transpile generators:
{
"name": "pos_lisa-api",
"version": "0.1.0",
"description": "LISA POS REST API",
"scripts": {
"lint": "standard",
"test": "npm run lint && ava"
},
"author": "Mauricio Cano Giraldo",
"license": "MIT",
"devDependencies": {
"ava": "^0.18.1",
"babel-eslint": "^7.1.1",
"babel-register": "^6.23.0",
"standard": "^8.6.0",
"test-listen": "^1.0.1"
},
"dependencies": {
"babel-plugin-transform-async-to-generator": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babel-runtime": "^6.22.0",
"http-hash": "^2.0.0",
"micro": "^7.0.6",
"request": "^2.79.0",
"request-promise": "^4.1.1",
"uuid-base62": "^0.1.0"
},
"standard": {
"parser": "babel-eslint"
},
"babel": {
"presets": [
"es2015"
],
"plugins": [
"transform-runtime",
"transform-async-to-generator"
]
}
}
And here is my node file, where i get the error:
'use strict'
import { send } from 'micro'
import httpHash from 'http-hash'
const hash = httpHash()
hash.set('GET /:id', async function getCliente (req, res, params) {
send(res, 200, params)
})
export default async function main (req, res) {
let method = req.method
let url = req.url
let match = hash.get(`${method.toUpperCase()} ${url}`)
if (match.handler) {
try {
await match.handler(req, res, match.params)
} catch (e) {
send(res, 500, { error: e.message })
}
} else {
send(res, 404, { error: 'La ruta no fue encontrada' })
}
}
I am reading around the web and I don't find anything. Please, help me! I would appreciate it so much!
AVA only transpiles the test files you want to run, but not the modules you're importing in them. But you can tell AVA to also transpile the imported modules by requiring babel-register (https://github.com/avajs/ava#transpiling-imported-modules). And because you configured babel already you can also tell it to use your config. Add this to your package.json
"ava": {
"babel": "inherit",
"require": ["babel-register"]
}
If you'd like to use the babel config AVA uses, you can leave off the "babel": "inherit", or you can define an entirely different one if you wish. But usually it's best to just inherit your config.
Using a .babelrc instead may work.