Having problem with path (nodejs botbuilder) - javascript

I'm working on a bot using Bot Framework, .env file and a JSON file.
The problem is I can't seem to get the icon to show up unless I set the path manually as shown below:
var invite = new Welcome(process.env.IconUrl = "C:/Users/2203609/Desktop/Mybot/bot.jpg");
That is not a practical way as we will need to change the path manually every time we transfer over to another computer. So I came up with this idea. I will show my .js, .env and .json files.
I create 3 variables namely:
.js:
const loc = '\\bot.jpg';
const pathname = __dirname;
const assa = pathname + loc;
class welcome(){
constructor(IconUrl, botVersion) {
this.IconUrl = IconUrl
this.BotVersion = botVersion
}
}
async Menu(turnContext) {
var invite = new Welcome(process.env.IconUrl = assa);
await turnContext.sendActivity({
attachments: [invite.welcome()]
});
}
.env:
IconUrl =
"items": [{
"type": "Image",
"style": "Person",
"url": "%IconUrl%",
"size": "Large"
}],
The output for this is:
[onTurnError]: SyntaxError: Unexpected token U in JSON at position 633
UPDATE: the variable pathname cannot be used as parameter in welcome class.

There are some errors in how you structured your code. If you wish to display an image you need to use a card. In the example below, I'm using a hero card.
Also, the 'onTurn' method must keep that name. You can create other methods within the class that have their own name. These would reflect different steps within a waterfall dialog. You can read more about waterfall dialogs here.
const { ActivityTypes, CardFactory } = require('botbuilder');
const loc = '\\bot.jpg';
const pathname = __dirname;
const assa = pathname + loc;
const hero = CardFactory.heroCard(
'Hero Card',
CardFactory.images([assa])
);
class Welcome {
constructor(IconUrl, botVersion) {
this.IconUrl = IconUrl;
this.BotVersion = botVersion;
}
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
if (!turnContext.responded) {
const reply = { type: ActivityTypes.Message };
reply.attachments = [hero];
return await turnContext.sendActivity(reply);
}
}
}
}
module.exports.Welcome = Welcome;
I would recommend reading thru the docs. Even more so, I would recommend you look over the various samples on the Botbuilder-Samples GitHub repo. Each sample builds on the previous and introduces core ideas and best practices.
Hope of help!

Related

How can import a global variable into another file?

I am trying to use a global accessToken variable within another file but I keep getting the error Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\Users\Taat\Documents\Backend\server\controllers\authController' imported from C:\Users\Taat\Documents\Backend\server\controllers\dataController.js code: 'ERR_MODULE_NOT_FOUND'
where I am exporting it within authController and importing it within dataController as you can see below in the code:
authController.js:
export let accecssToken;
// rest of my code
dataController.js:
import { accecssToken } from "./authController";
export async function getActivityId(req, res) {
const data = await getDataPromise();
const activityIds = {};
for (let i = 0; i < data.length(); i++) {
activityIds[data[i].id] = [];
}
return res.json(activityIds);
}
export async function getDataPromise() {
const link = `api/?access_token=${accecssToken}`;
console.log("Link = ", link);
const response = await axios.get(link);
return response.data;
}
I do not see what I am doing wrong here can anyone spot it?
Both files are in the same directory as you can see from the error messages paths
Just add extension of exported file
import { accecssToken } from "./authController.js";
or You can use
const { accecssToken } = require('./authController');
Use -
const {accessToken} = require("./authController");
Though seeing the naming convention and your code you're utilizing the accessToken, I would not recommend adding SECERTS in js files as it could be compromised.
Make a .env file at the root folder and add all secrets inside.
.env file should look like -
To use any .env variable, add
require("dotenv").config();
and then use -
const link = `api/?access_token=${process.env.ACCESS_TOKEN}`

Reading a web page with node.js and urllib

I'm learning programming and found myself in a tough spot; the code from the tutorial is not working and I can't understand why.
It's a shell script that's supposed to retrieve a wikipedia page, strip it of the references, and return just the paragraphs text.
It uses the urllib library. In the code below, the only difference from the tutorial's is the use of fs to make a text file with the page content. The rest is copied and pasted.
#!/usr/local/bin/node
// Returns the paragraphs from a Wikipedia link, stripped of reference numbers.
let urllib = require("urllib");
let url = process.argv[2];
let fs = require("fs");
console.log(url);
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
urllib.request(url, { followRedirect: true }, function(error, data, response) {
let body = data.toString();
// Simulate a Document Object Model.
let { document } = (new JSDOM(body)).window;
// Grab all the paragraphs and references.
let paragraphs = document.querySelectorAll("p");
let references = document.querySelectorAll(".reference");
// Remove any references.
references.forEach(function(reference) {
reference.remove();
});
// Print out all of the paragraphs.
paragraphs.forEach(function(paragraph) {
console.log(paragraph.textContent);
fs.appendFileSync("article.txt", `${paragraph}\n`);
});
});
My first guess, was that urllib was not working for some reason. This cause, even if I installed it as per official documentation, when I type which urllib at the command line, it doesn't return a path.
But then, node doesn't return an error for not knowing what the require("urllib") is when I run the file.
The actual output is the following:
$ ./wikp https://es.wikipedia.org/wiki/JavaScript
https://es.wikipedia.org/wiki/JavaScript
$
Can anybody help please?
I think the tutorial you followed might have been a little out of date.
This works for me:
let urllib = require("urllib");
let url = process.argv[2];
let fs = require("fs");
console.log(url);
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
urllib.request(url, { followRedirect: true }).then(({data, res}) => {
let body = data.toString();
// Simulate a Document Object Model.
let { document } = (new JSDOM(body)).window;
// Grab all the paragraphs and references.
let paragraphs = document.querySelectorAll("p");
let references = document.querySelectorAll(".reference");
// Remove any references.
references.forEach(function(reference) {
reference.remove();
});
// Print out all of the paragraphs.
paragraphs.forEach(function(paragraph) {
console.log(paragraph.textContent);
fs.appendFileSync("article.txt", `${paragraph.textContent}\n`);
});
});
The package you are using (urllib) is using promises, that might have been different in the past, when the tutorial was released.

How to Add Color to Static Mapbox Image Gotten from API

Below is the URL I pass to fetch API to get the image. It works great but the location pin is grey and I need it to be #800080 (purple). I get there's a marker-color parameter but not sure how to add it to the baseUrl string below. I've tried several different versions.
const baseUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/geojson(%7B%22type%22%3A%22Point%22%2C%22coordinates%22%3A%5B${geoLocation.longitude}%2C${geoLocation.latitude}%5D%7D)/${geoLocation.longitude},${geoLocation.latitude},15/500x300?access_token=${MAPBOX_API_KEY}`;
Relevant documentation which gives additional parameters but no clear examples: https://docs.mapbox.com/api/maps/static-images/#overlay-options
Code:
const getUrlExtension = (url) => {
return url.split(/[#?]/)[0].split('.').pop().trim();
};
const onImageEdit = async (imgUrl) => {
const imgExt = getUrlExtension(imgUrl);
const response = await fetch(imgUrl);
const blob = await response.blob();
const file = new File([blob], 'locationImage.' + imgExt, {
type: blob.type,
});
setImage(file);
setPreviewSrc(response.url);
};
function previewLocation(event) {
event.preventDefault();
const MAPBOX_API_KEY ='xyz';
// baseUrl based on https://docs.mapbox.com/api/maps/static-images/#overlay-options
const baseUrl = `https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/geojson(%7B%22type%22%3A%22Point%22%2C%22coordinates%22%3A%5B${geoLocation.longitude}%2C${geoLocation.latitude}%5D%7D)/${geoLocation.longitude},${geoLocation.latitude},15/500x300?access_token=${MAPBOX_API_KEY}`;
onImageEdit(baseUrl);
}
Thanks in advance to anyone with Mapbox API experience!
I am unable to get the GeoJSON method to respond to the properties key too! Not sure what's going on there...
I am however able to get a pin showing in that color using the Marker method like the below.
https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/pin-s-l+800080(-87.0186,32.4055)/-87.0186,32.4055,14/500x300?access_token=YOUR_TOKEN_HERE.

Connecting to a running process in Winappdriver using Javascript

I am fairly new to JS/Winappdriver.
The application I am trying to test is a windows based "Click Once" application from .Net, so I have to go to a website from IE and click "Install". This will open the application.
Once the application is running, I have no way to connect the application to perform my UI interactions while using JavaScript.
Using C#, I was looping through the processes looking for a process name, get the window handle, convert it to hex, add that as a capability and create the driver - it worked. Sample code below,
public Setup_TearDown()
{
string TopLevelWindowHandleHex = null;
IntPtr TopLevelWindowHandle = new IntPtr();
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith($"SomeName-{exec_pob}-{exec_env}"))
{
TopLevelWindowHandle = clsProcess.Handle;
TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
}
}
var appOptions = new AppiumOptions();
appOptions.AddAdditionalCapability("appTopLevelWindow", TopLevelWindowHandleHex);
appOptions.AddAdditionalCapability("ms:experimental-webdriver", true);
appOptions.AddAdditionalCapability("ms:waitForAppLaunch", "25");
AppDriver = new WindowsDriver<WindowsElement>(new Uri(WinAppDriverUrl), appOptions);
AppDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);
}
How do I do this in Javascript ? I can't seem to find any code examples.
Based on an example from this repo, I tried the following in JS to find the process to latch on to but without luck.
import {By2} from "selenium-appium";
// this.appWindow = this.driver.element(By2.nativeAccessibilityId('xxx'));
// this.appWindow = this.driver.element(By2.nativeXpath("//Window[starts-with(#Name,\"xxxx\")]"));
// this.appWindow = this.driver.elementByName('WindowsForms10.Window.8.app.0.13965fa_r11_ad1');
// thisappWindow = this.driver.elementByName('xxxxxxx');
async connectAppDriver(){
await this.waitForAppWindow();
var appWindow = await this.appWindow.getAttribute("NativeWindowHandle");
let hex = (Number(ewarpWindow)).toString(16);
var currentAppCapabilities =
{
"appTopLevelWindow": hex,
"platformName": "Windows",
"deviceName": "WindowsPC",
"newCommandTimeout": "120000"
}
let driverBuilder = new DriverBuilder();
await driverBuilder.stopDriver();
this.driver = await driverBuilder.createDriver(currentEwarpCapabilities);
return this.driver;
}
I keep getting this error in Winappdriver
{"status":13,"value":{"error":"unknown error","message":"An unknown error occurred in the remote end while processing the command."}}
I've also opened this ticket here.
It seems like such an easy thing to do, but I couldn't figure this one out.
Any of nodes packages I could use to get the top level window handle easily?
I am open to suggestions on how to tackle this issue while using JavaScript for Winappdriver.
Hope this helps some one out there,
Got around this by creating an exe using C# that generated hex of the app to connect based on the process name, it looks like something like this.
public string GetTopLevelWindowHandleHex()
{
string TopLevelWindowHandleHex = null;
IntPtr TopLevelWindowHandle = new IntPtr();
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith(_processName))
{
TopLevelWindowHandle = clsProcess.Handle;
TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
}
}
if (!String.IsNullOrEmpty(TopLevelWindowHandleHex))
return TopLevelWindowHandleHex;
else
throw new Exception($"Process: {_processName} cannot be found");
}
Called it from JS to get the hex of the top level window handle, like this,
async getHex () {
var pathToExe =await path.join(process.cwd(), "features\\support\\ProcessUtility\\GetWindowHandleHexByProcessName.exe");
var pathToDir =await path.join(process.cwd(), "features\\support\\ProcessUtility");
const result = await execFileSync(pathToExe, [this.processName]
, {cwd: pathToDir, encoding: 'utf-8'}
, async function (err, data) {
console.log("Error: "+ err);
console.log("Data(hex): "+ data);
return JSON.stringify(data.toString());
});
return result.toString().trim();
}
Used the hex to connect to the app like this,
async connectAppDriver(hex) {
console.log(`Hex received to connect to app using hex: ${hex}`);
const currentAppCapabilities=
{
"browserName": '',
"appTopLevelWindow": hex.trim(),
"platformName": "Windows",
"deviceName": "WindowsPC",
"newCommandTimeout": "120000"
};
const appDriver = await new Builder()
.usingServer("http://localhost:4723/wd/hub")
.withCapabilities(currentAppCapabilities)
.build();
await driver.startWithWebDriver(appDriver);
return driver;
}
Solution:
In WebDriverJS (used by selenium / appium), use getDomAttribute instead of getAttribute. Took several hours to find :(
element.getAttribute("NativeWindowHandle")
POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
Command not implemented: POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
HTTP/1.1 501 Not Implemented
let topLevelWindowHandle = await element.getDomAttribute('NativeWindowHandle')
topLevelWindowHandle = parseInt(topLevelWindowHandle).toString(16)
GET /session/DE4C46E1-CC84-4F5D-88D2-35F56317E34D/element/42.3476754/attribute/NativeWindowHandle HTTP/1.1
HTTP/1.1 200 OK
{"sessionId":"DE4C46E1-CC84-4F5D-88D2-35F56317E34D","status":0,"value":"3476754"}
and topLevelWindowHandle have hex value :)

Can't save/create files using Store.js

So I wanted to save a file on the client storage using Store.js.
I can change the date using store.set and i can log it to console to see the change, but then it's supposed to be saved in app data where it's not created.
I tried to get the Path where it's being saved and it's :
C:\Users\USER\AppData\Roaming\stoma2/Categories.json
I noticed that there is a "/" so I tried :
C:\Users\USER\AppData\Roaming\stoma2\Categories.json
and :
C:/Users/USER/AppData/Roaming/stoma2/Categories.json
But all 3 of them didn't work.
This is my Store.js :
const fs = require('browserify-fs');
var fs2 = require('filereader'),Fs2 = new fs2();
const electron = window.require('electron');
const path = require('path');
class Store {
constructor(opts) {
// Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
// app.getPath('userData') will return a string of the user's app data directory path.
//const userDataPath = (electron.app || electron.remote.app).getPath('userData');
var userDataPath = (electron.app || electron.remote.app).getPath('userData');
for(var i=0;i<userDataPath.length;i++){
if(userDataPath.charAt(i)=="\\"){
userDataPath = userDataPath.replace("\\","/");
}
}
// We'll use the `configName` property to set the file name and path.join to bring it all together as a string
this.path = path.join(userDataPath, opts.configName + '.json');
this.data = parseDataFile(this.path, opts.defaults);
console.log(this.path);
}
// This will just return the property on the `data` object
get(key) {
return this.data[key];
}
// ...and this will set it
set(key, val) {
this.data[key] = val;
// Wait, I thought using the node.js' synchronous APIs was bad form?
// We're not writing a server so there's not nearly the same IO demand on the process
// Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
// we might lose that data. Note that in a real app, we would try/catch this.
fs.writeFile(this.path, JSON.stringify(this.data));
}
}
function parseDataFile(filePath, data) {
// We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
// `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
try {
return JSON.parse(Fs2.readAsDataURL(new File(filePath)));
} catch(error) {
// if there was some kind of error, return the passed in defaults instead.
return data;
}
}
// expose the class
export default Store;
There might be a probleme fith js.writeFile() (well that's the source of probleme).
and this is my call :
//creation
const storeDefCat = new Store({
configName: "Categories",
defaults: require("../data/DefaultCategorie.json")
})
//call for the save
storeDefCat.set('Pizza',{id:0,path:storeDefCat.get('Pizza').path});
For now if possible,I might need to find another way to save the file.
And i tried : fs : It doesn't work for me for some reason (I get strange errors that they don't want to be fixed..) .
If anyone has an Idea then please I would be grateful.
So I managed to fix the probleme, Why fs was sending me errors about undefined functions?Why file wasn't getting created ? It has NOTHING to do with the code it self, but the imports...
To clearify, I was using :
const fs = require('fs');
And the solution is to make it like :
const fs = window.require('fs');
Just adding window. fixed all the problems .Since it's my first time using electron I wasn't used to import from the window but it seems it's necessary.And more over...There was no posts saying this is the fix.

Categories