Error while trying to call detectintent api in nodejs-Dialogflow CX - node.js

I am trying to send a request to DetectIntent API from webhook - Dialog Flow CX . I downloaded service-key in GCP and stored in serviceaccount.json file .I created .env file and stored all the values from serviceaccount file to .env file.I get error when I run "node index.js"
Error:"IAM permission 'dialogflow.sessions.detectIntent' on 'projects/dialogflowcx-340818,/agent' denied.",
I went through related stackoverflow posts where they suggested to set GOOGLE_APPLICATION_CREDENTIALS .I tried that as well.Still I get the same error.
I tried :
process.env.GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
Also,I tried to set
export GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
Please find the code below:
const dialogflow = require('#google-cloud/dialogflow');
test=require('dotenv').config();
const express = require('express');
const path = require("path");
process.env.GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
const PROJECTID = process.env.project_id;
const location=process.env.location
const agentid=process.env.agentid
const CONFIGURATION = {
credentials: {
private_key: process.env.private_key,
client_email: process.env.client_email
}
}
const sessionClient = new dialogflow.SessionsClient();
const detectIntent = async (languageCode, queryText, sessionId) => {
let sessionPath = sessionClient.projectLocationAgentSessionPath(PROJECTID,location,agentid,sessionId);
// The text query request.
let request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: queryText,
// The language used by the client (en-US)
languageCode: languageCode,
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log(responses);
const result = responses[0].queryResult;
console.log(result);
return {
response: result.fulfillmentText
};
}
detectIntent("en", "hello", "abcd1234");
// Start the webapp
const webApp = express();
// Webapp settings
webApp.use(express.urlencoded({
extended: true
}));
webApp.use(express.json());
// Server Port
const PORT = process.env.PORT || 5000;
// Home route
webApp.get('/', (req, res) => {
res.send(`Hello World.!`);
});
// Dialogflow route
webApp.post('/dialogflow', async (req, res) => {
let languageCode = req.body.languageCode;
let queryText = req.body.queryText;
let sessionId = req.body.sessionId;
let responseData = await detectIntent(languageCode, queryText, sessionId);
res.send(responseData.response);
});
// Start the server
webApp.listen(PORT, () => {
console.log(`Server is up and running at ${PORT}`);
});
Please find .env file below:
type= service_account,
project_id=xxx,
private_key_id=xxx,
private_key=xxx","client_email": "xxx","client_id": "xxx","auth_uri": "xxx,
token_uri=xxx,
auth_provider_x509_cert_url= xxx,
client_x509_cert_url=xxx
location=xxx
agentid=xxx

Related

Write streaming testcase in jest for download from remote url

I have the following API /api/v1/download/:id
Usage: http://localhost:3000/api/v1/download/client_app.zip
Implementation:
const express = require("express");
const axios = require("axios");
const { InternalServerError } = require("common-lib");
const router = express.Router();
router.get("/api/v1/download/:id",
async (req, res, next) => {
const { id } = req.params;
try {
const response = await axios.get(
`${process.env.DOWNLOAD_URL}/artifacts/client_app/${id}`, {
auth: {
username: process.env.USERNAME,
password: process.env.PASSWORD
},
responseType: "stream"
});
response.data.pipe(res);
} catch (error) {
return next(new InternalServerError(error.message));
}
});
module.exports = {
downloadByIdRouter: router
}
A user will use the /api/v1/download/:id to download the .zip file from another remote server, the actual credentials and remote URL are hidden from the end-user.
The API is working as expected and I am able to download the file into my system.
The question is how to write the test for this particular streaming scenario in Jest.
describe("download by id test", () => {
test("downloads the app, if requested properly", () => {
// to do
}, )
});
I checked this reference https://dev.to/cdanielsen/testing-streams-a-primer-3n6e. However, I am not exactly getting the approach.
I need guidance in writing the test for this particular scenario, comparatively new to Jest.
Route import
const express = require("express");
// Import routes
const { downloadByIdRouter } = require("./routes/download-byid");
const app = express();
// Use routes
app.use(downloadByIdRouter);
module.exports = {
app
}
Then I import app in the test file and using the supertest library I make the API calls
download.test.js
const request = require("supertest");
const { app } = require("../../app");
describe("download by id test", () => {
test.todo("starts the app download, if requested properly")
});
Thanks

Cannot set headers after they are sent to the client?

Here I'm trying to GET data from server, But when I try to open the browser and get the data nothing appear, Its give me the same URL in the browser.
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]:
// Application Dependencies
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const superAgent = require('superagent');
// Application Setup
const PORT = process.env.PORT || 3000;
const app = express();
app.use(cors());
//KEYS
const WEATHER_API_KEY = process.env.WEATHER_API_KEY;
const GEOCODE_API_KEY = process.env.GEOCODE_API_KEY;
const PARK_KEY = process.env.PARK_KEY;
//Route Definitions
app.get('/location', locationHandler);
app.get('/weather', weatherHandler);
app.get('/parks', parksHandler);
app.get('*', errorHandler);
//Location Handler
async function locationHandler(req, res) {
try {
console.log(req.query);
let getCity = req.query.city;
let url = `https://us1.locationiq.com/v1/search.php?key=pk.9e079e96352c63d18cf387532fa6b9ad&q=seattle&format=json`;
const locationData = await superAgent.get(url);
const apiData = JSON.parse(locationData.text);
console.log(superAgent.get(url))
res.send(superAgent.get(url));
// let aaa = new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon);
// console.log(aaa);
res.status(200).send(new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon));
} catch (error) {
res.status(404).send('Something went wrong in LOCATION route')
}
}
The response object does not batch an entire response necessarily, and might start sending it as available. HTTP requires that headers are written before anything else. Once anything else is written, it becomes impossible to send headers, such as changing the status code.
You might refactor the code to send the status first:
res.status(200)
res.send(superAgent.get(url));
res.send(new City(getCity, apiData[0].display_name, apiData[0].lat, apiData[0].lon));
} catch (error) {
You cannot send a response more then once.
So remove this line: res.send(superAgent.get(url));

Embedded Custom NextJS App on Shopify Storefront changes asset file paths

I'm wondering if anyone could help me. I have built a custom NextJS app on Heroku intended to be embedded on my Shopify storefront using Shopify's app proxy. It's mostly working, so it is showing my app when I go to the proxy url within my Shopify store however all of the CSS & JS filepaths have been changed to my Shopify URL rather than remaining as my Heroku app URL.
I have seen someone else have this exact same problem: https://community.shopify.com/c/Shopify-APIs-SDKs/App-Proxy-Sending-index-html-throws-404-on-the-JS-and-CSS-files/td-p/586595
However when I try to implement this solution it keeps breaking the app. I'm relatively new to Node.js/Next.js so while I'm still learning I largely depend on documentation to follow to set up or resolve this type of issue. However, I cannot find any tutorials or documentation specific to this issue.
Is anyone able to advise what I need to do within my server.js to make the '/_next/static/...' files remain to be pulled from my Heroku app URL rather than the Shopify URL when being viewed from the proxy URL? I have included the contents of my server.js file below.
require('isomorphic-fetch');
const dotenv = require('dotenv');
const Koa = require('koa');
const next = require('next');
const { default: createShopifyAuth } = require('#shopify/koa-shopify-auth');
const { verifyRequest } = require('#shopify/koa-shopify-auth');
const { default: Shopify, ApiVersion } = require('#shopify/shopify-api');
const Router = require('koa-router');
dotenv.config();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SHOPIFY_API_SCOPES.split(","),
HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(() => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
apiKey: process.env.SHOPIFY_API_KEY,
secret: process.env.SHOPIFY_API_SECRET,
scopes: ["read_products"],
afterAuth(ctx) {
const { shop, scope } = ctx.state.shopify;
ACTIVE_SHOPIFY_SHOPS[shop] = scope;
ctx.redirect(`/?shop=${shop}`);
},
}),
);
const handleRequest = async (ctx) => {
console.log('ctx.req.url', ctx.req.host);
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
router.get("/", async (ctx) => {
const shop = ctx.query.shop;
ACTIVE_SHOPIFY_SHOPS[shop] = ctx.query.shop;
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
});
router.get("/_next/*", handleRequest);
router.get("(.*)", verifyRequest(), handleRequest);
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Many thanks
A Proxy is simply a callback to your App, where as a response you provide either Liquid, or JSON. If you are trying to return links to assets such as CSS or JS, links are just strings. So can just send them as JSON key:value pairs.
A simple workaround is to use assetPrefix on next.config.js.
The assetPrefix will be prefixed for the /_next/ path automatically, so the assets are refered with absolute URL.
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
assetPrefix: isProd ? 'https://yourappdomain.com' : '',
}
https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix

include a verificationToken or clientSigningSecret to verify incoming Events API webhooks

I am trying to develop a chatbot using microsoft bot framework and I am also using botbuilder-adaptor-slack npm package to connect it to slack. This is following code which I have written in javascript:
const restify = require('restify');
const { BotFrameworkAdapter, UserState, MemoryStorage } = require('botbuilder');
const {SlackAdapter} = require('botbuilder-adapter-slack')
const WelcomeBot = require('./functions/welcomebot')
const memoryStorage = new MemoryStorage();
const userState = new UserState(memoryStorage);
const bot = new WelcomeBot.WelcomeBot(userState);
const adapter = new SlackAdapter({clientSigningSecret:process.env.CLIENT_SECRET,
verificationToken:process.env.verificationToken,
botToken:process.env.SLACK_TOKEN,
oauthVersion: 'v2'
});
adapter.onTurnError = async(context,error) => {
}
let server = restify.createServer()
server.use(restify.plugins.bodyParser());
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async(context) => {
console.log(req.body)
await bot.run(context);
})
})
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${server.name} listening to ${server.url}`);
});
I am getting the following error when I am trying to run the code.
Can somebody please help me with this code?
Looks like you're missing your auth information. You need to either:
Run in debug mode with a breakpoint on const adapter = new SlackAdapter... and ensure that process.env.<variable>, or
Add console.log(JSON.stringify(process.env, null, 2))
to ensure your environment variables (process.env.CLIENT_SECRET, process.env.verificationToken, and process.env.SLACK_TOKEN) are actually being set and exist.
If they are, then one of them is incorrect.
If they are not set or don't exist in process.env, you likely need to:
Create a .env file with:
CLIENT_SECRET=<yourClientSecret>
verificationToken=<yourVerificationToken>
SLACK_TOKEN=<yourSlackToken>
Note: Capitalization matters!
Add the following to your code, just after your import statements:
const dotenv = require('dotenv');
// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });
I'd wager your issue is just that you're missing this code

Client side CORS error with cloud functions and Firebase

I am new to firebase and wanting to use their HTTP cloud functions. When I try to go to any endpoint (not using the emulator - eg https://us-central1-xxxxxxxx.cloudfunctions.net/app/api/admin/studio) I am getting CORS errors.
Here is an example of my code. I have no security rules set currently (still in development). The code below works perfect when using the firebase emulator. Just not using the "live" .cloudfunctions link.
Is there a permission or set up I am missing? This endpoint works if you access this directly via the browser or POSTMAN, just not from the react app.
An example of the error from the react app is:
Origin https://xxxxxxxxxxx is not allowed by Access-Control-Allow-Origin.
Fetch API cannot load https://us-central1-xxxxxxxx.cloudfunctions.net/app/api/admin/studio due to access control checks.
index.js
const functions = require("firebase-functions")
const express = require("express")
const app = express()
const cors = require("cors")({ origin: true })
app.use(cors)
const studio = require("./http/studio.js")
app.post("/api/admin/studio", studio.add)
exports.app = functions.https.onRequest(app)
db.js
const admin = require("firebase-admin")
admin.initializeApp()
module.exports = admin.firestore()
http/studio.js
const db = require("../db")
const error = require("./error")
exports.add = (req, res) => {
const { data } = req.body
if (!data) {
return error.no_data(res)
}
return db
.collection("data")
.doc("studio")
.update({ values: admin.firestore.FieldValue.arrayUnion(data) })
.then(res.status(200).send("Data updated successfully"))
.catch(err => error.updating(res, err))
}
I was able to fix with updating my index.js code to include a list of allowed origins.
const functions = require("firebase-functions")
const express = require("express")
const app = express()
const cors = require("cors")({ origin: true })
var allowedOrigins = ["https://domainone", "https://domaintwo"]
app.use(
cors({
origin: function(origin, callback) {
if (!origin) return callback(null, true)
if (allowedOrigins.indexOf(origin) === -1) {
var msg = "The CORS policy for this site does not " + "allow access from the specified Origin."
return callback(new Error(msg), false)
}
return callback(null, true)
}
})
)
const studio = require("./http/studio.js")
app.post("/api/admin/studio", studio.add)
exports.app = functions.https.onRequest(app)

Resources