Microsoft bot builder V4 nodejs fetching user email - node.js

i am using nodejs v4 version of the botbuilder https://learn.microsoft.com/en-us/javascript/api/botbuilder/?view=botbuilder-ts-latest
My current code is picked from echo bot and looks like below
const { ActivityHandler } = require('botbuilder');
class ScanBuddyMsBot extends ActivityHandler {
constructor() {
super();
this.onMessage(async (context:any, next:any) => {
await context.sendActivity(`You said '${ context.activity.text }'`);
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
}
module.exports.ScanBuddyMsBot = ScanBuddyMsBot;
I am looking a way to fetch user email sending message to my bot. I can see in the context activity, conversation id and service url but not the email id.
in another variation of this i am using below way to get email id and not sure how to make below code work for above
var bot = new builder.UniversalBot(connector, async function(session) {
var teamId = session.message.address.conversation.id;
connector.fetchMembers(
session.message.address.serviceUrl,
teamId,
async (err, result) => {
if (err) {
session.send('We faced an error trying to process this information', err);
return
}
else {
const email = result[0].email
}

In Bot Builder v4, you can access that REST API using the getConversationMembers function:
/**
*
* #param {TurnContext} turnContext
*/
async testTeams(turnContext) {
const activity = turnContext.activity;
const connector = turnContext.adapter.createConnectorClient(activity.serviceUrl);
const response = await connector.conversations.getConversationMembers(activity.conversation.id);
const email = response[0].email;
await turnContext.sendActivity(email);
}
Please refer to the documentation and the samples to better understand how to use the v4 SDK.

Related

Add authentication and Qnamaker to bot

I am trying to build a bot using bot framework sdk.
Objective:-
To authenticate user.
afte authentication communicate with Qnamaker knowledge base.
signout user if he types logout
I am using bot authentication template from https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/javascript_nodejs/18.bot-authentication. I have tried to add qnamaker service in the waterflowdialog.
I am facing two issues:-
With every Qnamaker reply I am getting message "you are now logged in".
Bot encountered an error.
Source Code
mainDialog.js
const {
ConfirmPrompt,
DialogSet,
DialogTurnStatus,
OAuthPrompt,
WaterfallDialog,
} = require("botbuilder-dialogs");
const { LogoutDialog } = require("./logoutDialog");
const { QnAMakerDialog } = require("botbuilder-ai");
const CONFIRM_PROMPT = "ConfirmPrompt";
const MAIN_DIALOG = "MainDialog";
const MAIN_WATERFALL_DIALOG = "MainWaterfallDialog";
const OAUTH_PROMPT = "OAuthPrompt";
const QNAMAKER_BASE_DIALOG = "qnamaker-base-dialog";
const createQnAMakerDialog = (
knowledgeBaseId,
endpointKey,
endpointHostName,
defaultAnswer
) => {
let noAnswerActivity;
if (typeof defaultAnswer === "string") {
noAnswerActivity = MessageFactory.text(defaultAnswer);
}
const qnaMakerDialog = new QnAMakerDialog(
knowledgeBaseId,
endpointKey,
endpointHostName,
noAnswerActivity
);
qnaMakerDialog.id = QNAMAKER_BASE_DIALOG;
return qnaMakerDialog;
};
class MainDialog extends LogoutDialog {
constructor(knowledgeBaseId, endpointKey, endpointHostName, defaultAnswer) {
super(MAIN_DIALOG, process.env.connectionName);
this.addDialog(
new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.connectionName,
text: "Please Sign In",
title: "Sign In",
timeout: 300000,
})
);
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(
new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.loginStep.bind(this),
this.qnaMaker.bind(this),
])
);
this.addDialog(
createQnAMakerDialog(
knowledgeBaseId,
endpointKey,
endpointHostName,
defaultAnswer
)
);
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} dialogContext
*/
async run(context, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(context);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
async qnaMaker(stepContext) {
await stepContext.beginDialog(QNAMAKER_BASE_DIALOG);
}
async promptStep(stepContext) {
return await stepContext.beginDialog(OAUTH_PROMPT);
}
async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity("You are now logged in");
return await stepContext.next();
}
await stepContext.context.sendActivity(
"Login was not successful please try again."
);
return await stepContext.endDialog();
}
}
module.exports.MainDialog = MainDialog;
Bot ScreenShot
github link : https://github.com/chandelsumeet/authBot
async loginStep(stepContext) {
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
const tokenResponse = stepContext.result;
if (tokenResponse) {
await stepContext.context.sendActivity('You are now logged in.');
return await stepContext.prompt(CONFIRM_PROMPT, 'Would you like to view your token?');
}
await stepContext.context.sendActivity('Login was not successful please try again.');
return await stepContext.endDialog();
}
Replace the loginStep() with above code block and check it.

TypeError: Cannot perform 'get' on a proxy that has been revoked

I am trying to use context in cron.schedule()
this.onTeamsMembersAddedEvent(async (membersAdded, teamInfo, turnContext, next) => {
const members = await TeamsInfo.getTeamMembers(turnContext);
const channels = await TeamsInfo.getTeamChannels(turnContext);
const teamDetails = await TeamsInfo.getTeamDetails(turnContext);
let msteam = await msTeamsWorkspace.findOne({
teamName: teamDetails.name,
teamID: teamDetails.id,
channelID: channels[0].id
});
cron.schedule("* * * * * *", async function(){
var manager_detail = await Users.findById('5edb94e1182d254d5055775e')
turnContext.activity.conversation.id = manager_detail.conversationId;
await turnContext.sendActivity("Hey you got it");
});
await next();
});
Error :
TypeError: Cannot perform 'get' on a proxy that has been revoked
at Task.execution (K:\Project\MSTeams Bot\src\bot\bot.js:187:29)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Line 187:
turnContext.activity.conversation.id = manager_detail.conversationId;
Basically, this happens because context only exists until you call next(), so once the message is sent, the proxy that the bot uses is no longer available. This makes using callbacks, setInterval, setTimeout, and cron a bit tricky to use. The recommended route is to use Proactive Messages.
The key steps are to:
Save the bot adapter somewhere that you can use it. The sample does so here, but it also lives in turnContext.adapter (see below)
Save a conversationReference that you can refer back to. The sample does so here
Use the adapter and conversationReference to send a proactive message using continueConversation. The sample does so here
Exactly how you do that is up to you and the use case for your bot. But here's a quick code sample to show it works with cron:
const { ActivityHandler, MessageFactory, TurnContext } = require('botbuilder');
const cron = require('node-cron');
var conversationReferences = {};
var adapter;
class EchoBot extends ActivityHandler {
constructor() {
super();
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
this.onMessage(async (context, next) => {
const replyText = `Echo: ${ context.activity.text }`;
await context.sendActivity(MessageFactory.text(replyText, replyText));
const currentUser = context.activity.from.id;
conversationReferences[currentUser] = TurnContext.getConversationReference(context.activity);
adapter = context.adapter;
cron.schedule('* * * * * *', async function() {
await adapter.continueConversation(conversationReferences[currentUser], async turnContext => {
await turnContext.sendActivity('proactive hello');
});
});
// By calling next() you ensure that the next BotHandler is run.
await next();
});
[...]

Botframework how to authenticate first and than use the token to make graph api calls

Auth Dialog:
import { ChoicePrompt, DialogSet, DialogTurnStatus, OAuthPrompt, TextPrompt, WaterfallDialog, ComponentDialog } from 'botbuilder-dialogs';
import GraphClient from '../graph-client';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';
const OAUTH_PROMPT = 'oAuthPrompt';
const CHOICE_PROMPT = 'choicePrompt';
const TEXT_PROMPT = 'textPrompt';
import moment = require('moment');
class AuthDialog extends ComponentDialog {
constructor() {
super('AuthDialog');
this.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.ConnectionName,
text: 'Please login',
title: 'Login',
timeout: 300000
}))
.addDialog(new TextPrompt(TEXT_PROMPT))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.processStep.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a TurnContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* #param {*} turnContext
* #param {*} accessor
*/
public async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
public async promptStep(step) {
return step.beginDialog(OAUTH_PROMPT);
}
public async processStep(step) {
if (step.result) {
// We do not need to store the token in the bot. When we need the token we can
// send another prompt. If the token is valid the user will not need to log back in.
// The token will be available in the Result property of the task.
const tokenResponse = step.result;
// If we have the token use the user is authenticated so we may use it to make API calls.
if (tokenResponse && tokenResponse.token) {
await step.context.sendActivity(`Logged in.`);
} else {
await step.context.sendActivity('something wrong happened.');
}
} else {
await step.context.sendActivity('We couldn\'t log you in. Please try again later.');
}
return await step.endDialog();
}
}
export default AuthDialog;
I have a main dailog which is connected to luis and based on the intent recognized it executes corrosponding code:
for ex i have this in some cases:
case 'CalendarEvents':
return stepContext.beginDialog('AuthDialog');
const calendar = await new GraphClient('token').events();
let eventsBuilder: string = '';
// tslint:disable-next-line: prefer-for-of
for (let index = 0; index < calendar.length; index++) {
const element = calendar[index];
eventsBuilder += '\r\n' + moment(element.start.dateTime).format('dddd, MMMM Do YYYY, h:mm:ss a') + ' - ' + element.subject;
}
await step.context.sendActivity(`${eventsBuilder}`);
So if the intent is CalendarEvents then authenticate and than make some graph api call.
The problem I currently have is that the call to graph api is made before the auth is finished, I would like so first user authenticate and than receives some token and use that token for fetching graph api calls!
any idea how to achieve the above?
Please see the Graph Auth Sample. In particular,
It gets the token in MainDialog:
return step.beginDialog(OAUTH_PROMPT);
[...]
if (step.result) {
const tokenResponse = step.result;
if (tokenResponse && tokenResponse.token) {
const parts = (step.values.command || '').toLowerCase().split(' ');
const command = parts[0];
switch (command) {
case 'me':
await OAuthHelpers.listMe(step.context, tokenResponse);
break;
case 'send':
await OAuthHelpers.sendMail(step.context, tokenResponse, parts[1]);
break;
case 'recent':
await OAuthHelpers.listRecentMail(step.context, tokenResponse);
break;
default:
await step.context.sendActivity(`Your token is ${ tokenResponse.token }`);
}
}
}
[...]
Then, OAuthHelpers uses the token:
static async sendMail(context, tokenResponse, emailAddress) {
[...]
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
await client.sendMail(
emailAddress,
'Message from a bot!',
`Hi there! I had this message sent from a bot. - Your friend, ${ me.displayName }`
);
await context.sendActivity(`I sent a message to ${ emailAddress } from your account.`);
}
This is how the sample works. For you, since you only want to do auth in the Auth dialog, you need to get the token from the user using the Auth dialog, then save it to their UserState, similar to this sample. You can then retrieve their UserState in any dialog and use the token if they have it.
Note
You can either use the Graph API through regular HTTP REST API requests, or use the Graph SDK like the sample does.

Send user notification every hour with Bot Framework NodeJS

I am developing a bot that sends users a message every hour on skype. It makes an API call and then sends a message containing the parsed message. I started with the welcomebot sample. I then used the switch statement to fire a setInterval()to send the message activity when the user sends a certain message but the message keeps sending even after I call clearinterval() I set to a different string. How can I make clearInterval() work? Or am I going about it the wrong way?
Index.js:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Import required packages
const path = require('path');
const restify = require('restify');
const axios = require('axios');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, UserState, ConversationState, MemoryStorage } = require('botbuilder');
const { WelcomeBot } = require('./bots/welcomeBot');
// Read botFilePath and botFileSecret from .env file
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
// Create bot adapter.
// See https://aka.ms/about-bot-adapter to learn more about bot adapter.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppID,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
await context.sendActivity('The bot encountered an error or bug.');
await context.sendActivity('To continue to run this bot, please fix the bot source code.');
};
// Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state store to persist the dialog and user state between messages.
// For local development, in-memory storage is used.
// CAUTION: The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, anything stored in memory will be gone.
const memoryStorage = new MemoryStorage();
const userState = new UserState(memoryStorage);
const conversationState = new ConversationState(memoryStorage);
// Create the main dialog.
const conversationReferences = {};
const bot = new WelcomeBot(userState, conversationReferences, conversationState);
// Create HTTP server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
console.log('\nTo talk to your bot, open the emulator select "Open Bot"');
});
// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// route to main dialog.
await bot.run(context);
});
});
const getBalance = async () => {
try {
return await axios.get('https://balance.com/getbalance', { //this returns a json object
headers: {
Authorization: xxxxx
}
});
} catch (error) {
console.error(error);
}
};
const retrieveBalance = async () => {
const balance = await getBalance();
if (balance.data.message) {
for (const conversationReference of Object.values(conversationReferences)) {
await adapter.continueConversation(conversationReference, async turnContext => {
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
await turnContext.sendActivity(balance.data.message);
});
}
}
};
module.exports.retrieveBalance = retrieveBalance;
Bot.js:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Import required Bot Framework classes.
const { ActionTypes, ActivityHandler, CardFactory, TurnContext } = require('botbuilder');
const balance = require('../index.js');
// Welcomed User property name
const CONVERSATION_DATA_PROPERTY = 'conversationData';
class WelcomeBot extends ActivityHandler {
/**
*
* #param {UserState} //state to persist boolean flag to indicate
* if the bot had already welcomed the user
*/
constructor(userState, conversationReferences, conversationState) {
super();
// Creates a new user property accessor.
// See https://aka.ms/about-bot-state-accessors to learn more about the bot state and state accessors.
this.userState = userState;
this.conversationReferences = conversationReferences;
this.conversationDataAccessor = conversationState.createProperty(CONVERSATION_DATA_PROPERTY);
// The state management objects for the conversation and user state.
this.conversationState = conversationState;
this.onConversationUpdate(async (context, next) => {
this.addConversationReference(context.activity);
await next();
});
this.onMessage(async (context, next) => {
this.addConversationReference(context.activity);
// Add message details to the conversation data.
// Display state data.
// Read UserState. If the 'DidBotWelcomedUser' does not exist (first time ever for a user)
// set the default to false.
// const didBotWelcomedUser = await this.welcomedUserProperty.get(context, false);
// Your bot should proactively send a welcome message to a personal chat the first time
// (and only the first time) a user initiates a personal chat with your bot.
// if (didBotWelcomedUser === false) {
// // The channel should send the user name in the 'From' object
// await context.sendActivity( 'This bot will send you your paystack balance every 5 minutes. To agree reply \'ok\'');
// // Set the flag indicating the bot handled the user's first message.
// await this.welcomedUserProperty.set(context, true);
// }
// This example uses an exact match on user's input utterance.
// Consider using LUIS or QnA for Natural Language Processing.
var text = context.activity.text.toLowerCase();
var myint;
switch (text) {
case 'ok':
myint = setInterval(async () => {
await balance.retrieveBalance();
}, 1000);
// eslint-disable-next-line template-curly-spacing
break;
case 'balance':
await balance.retrieveBalance();
break;
case 'no':
clearInterval(myint);
break;
case 'hello':
case 'hi':
await context.sendActivity(`You said "${ context.activity.text }"`);
break;
case 'info':
case 'help':
await this.sendIntroCard(context);
break;
default:
await context.sendActivity('This is a simple notification bot. ');
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
// Sends welcome messages to conversation members when they join the conversation.
// Messages are only sent to conversation members who aren't the bot.
this.onMembersAdded(async (context, next) => {
// Iterate over all new members added to the conversation
for (const idx in context.activity.membersAdded) {
// Greet anyone that was not the target (recipient) of this message.
// Since the bot is the recipient for events from the channel,
// context.activity.membersAdded === context.activity.recipient.Id indicates the
// bot was added to the conversation, and the opposite indicates this is a user.
if (context.activity.membersAdded[idx].id !== context.activity.recipient.id) {
await context.sendActivity('Welcome to the Nag Bot. If you want to get nagged with your balance type \'ok\', if you want your balance alone type \'balance. for info type \'info\'');
}
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
/**
* Override the ActivityHandler.run() method to save state changes after the bot logic completes.
*/
async run(context) {
await super.run(context);
// Save state changes
await this.userState.saveChanges(context);
await this.conversationState.saveChanges(context, false);
}
addConversationReference(activity) {
const conversationReference = TurnContext.getConversationReference(activity);
this.conversationReferences[conversationReference.conversation.id] = conversationReference;
}
async sendIntroCard(context) {
const card = CardFactory.heroCard(
'Welcome to Nag Bot balance checker!',
'Welcome to Paystack Nagbot.',
['https://aka.ms/bf-welcome-card-image'],
[
{
type: ActionTypes.OpenUrl,
title: 'Open your dashboard',
value: 'https://dashboard.paystack.com'
},
{
type: ActionTypes.OpenUrl,
title: 'Ask a question on twitter',
value: 'https://twitter.com/paystack'
},
{
type: ActionTypes.OpenUrl,
title: 'View docs',
value: 'https://developers.paystack.co/reference'
}
]
);
await context.sendActivity({ attachments: [card] });
}
}
module.exports.WelcomeBot = WelcomeBot;

Bot Framework v4 Node.js Location

I'm in the process of designing a chat bot and trying to find some Node.js sample code and/or documentation on how to implement the Azure Maps service as part of Bot Framework V4. There are many examples of how this is accomplished in V3, but there seems to be no examples of a V4 solution for Node.js. I'm looking to create a step in my botbuilder-dialog flow that would launch a simple "where do we ship it too" location dialog that would guide the user through the dialog and store the address results as part of that users profile. Any help or advice on this would be appreciated.
Yes, this is doable. I created a class (probably overkill, but oh well) in which I make my API call, with my supplied parameters, to get the map. I decided to use Azure Maps (vs Bing Maps) only because I was curious in how it differed. There isn't any reason you couldn't do this with Bing Maps, as well.
In the bot, I am using a component dialog because of how I have the rest of my bot designed. When the dialog ends, it will fall off the stack and return to the parent dialog.
In my scenario, the bot presents the user with a couple choices. "Send me a map" generates a map and sends it in an activity to the client/user. Anything else sends the user onward ending the dialog.
You will need to decide how you are getting the user's location. I developed this with Web Chat in mind, so I am getting the geolocation from the browser and returning it to the bot to be used when getMap() is called.
const { ActivityTypes, InputHints } = require('botbuilder');
const fetch = require('node-fetch');
class MapHelper {
async getMap(context, latitude, longitude) {
var requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow'
};
const result = await fetch(`https://atlas.microsoft.com/map/static/png?subscription-key=${ process.env.AZURE_MAPS_KEY }&api-version=1.0&layer=basic&zoom=13&center=${ longitude },${ latitude }&language=en-US&pins=default|al.67|la12 3|lc000000||'You!'${ longitude } ${ latitude }&format=png`, requestOptions)
.then(response => response.arrayBuffer())
.then(async result => {
const bufferedData = Buffer.from(result, 'binary');
const base64 = bufferedData.toString('base64');
const reply = { type: ActivityTypes.Message };
const attachment = {
contentType: 'image/png',
contentUrl: `data:image/png;base64,${ base64 }`
};
reply.attachments = [attachment];
await context.sendActivity(reply, null, InputHints.IgnoringInput);
})
.catch(error => {
if (error) throw new Error(error);
});
return result;
};
};
module.exports.MapHelper = MapHelper;
const { ChoicePrompt, ChoiceFactory, ComponentDialog, ListStyle, WaterfallDialog } = require('botbuilder-dialogs');
const { MapHelper } = require('./mapHelper');
const CONFIRM_LOCALE_DIALOG = 'confirmLocaleDialog';
const CHOICE_PROMPT = 'confirmPrompt';
class ConfirmLocaleDialog extends ComponentDialog {
constructor() {
super(CONFIRM_LOCALE_DIALOG);
this.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new WaterfallDialog(CONFIRM_LOCALE_DIALOG, [
this.askLocationStep.bind(this),
this.getMapStep.bind(this)
]));
this.initialDialogId = CONFIRM_LOCALE_DIALOG;
}
async askLocationStep(stepContext) {
const choices = ['Send me a map', "I'll have none of this nonsense!"];
return await stepContext.prompt(CHOICE_PROMPT, {
prompt: 'Good sir, may I pinpoint you on a map?',
choices: ChoiceFactory.toChoices(choices),
style: ListStyle.suggestedAction
});
}
async getMapStep(stepContext) {
const { context, context: { activity } } = stepContext;
const text = activity.text.toLowerCase();
if (text === 'send me a map') {
const { latitude, longitude } = activity.channelData;
const mapHelper = new MapHelper();
await mapHelper.getMap(context, latitude, longitude);
const message = 'Thanks for sharing!';
await stepContext.context.sendActivity(message);
return await stepContext.endDialog();
} else {
await stepContext.context.sendActivity('No map for you!');
return await stepContext.endDialog();
}
}
}
module.exports.ConfirmLocaleDialog = ConfirmLocaleDialog;
module.exports.CONFIRM_LOCALE_DIALOG = CONFIRM_LOCALE_DIALOG;
Hope of help!
---- EDIT ----
Per request, location data can be obtained from the browser using the below method. It is, of course, dependent on the user granting access to location data.
navigator.geolocation.getCurrentPosition( async (position) => {
const { latitude, longitude } = position.coords;
// Do something with the data;
console.log(latitude, longitude)
})

Resources