I am developing a web app bot on azure (v3) and I am using async methods but I can't seem to solve an issue which is SyntaxError: Unexpected token function.
I've tried updating my nodeJS from 6.9.4 to 8.9 but that didn't work. I also ran npm i -g azure-functions-core-tools#core but still nothing.
class OAuthHelpers {
/**
* Enable the user to schedule meeting and send an email attachment via the bot.
* #param {TurnContext} turnContext
* #param {TokenResponse} tokenResponse
* #param {*} emailAddress The email address of the recipient
*/
async function createevent(turnContext, tokenResponse, emailAddress) {
if (!turnContext) {
throw new Error('OAuthHelpers.createevent(): `turnContext` cannot be undefined.');
}
if (!tokenResponse) {
throw new Error('OAuthHelpers.createevent(): `tokenResponse` cannot be undefined.');
}
var client = new SimpleGraphClient(tokenResponse.token);
// Calls the Graph API with the subject and content message...
await client.createevent(
emailAddress,
`Lunch`,
`I will be taking everyone to lunch as a reward for your hardwork.`
);
// Success message...
await turnContext.sendActivity(`Success! I have scheduled a meeting with you and ${ emailAddress } have created an event on each of their calendars.`);
}
I want the bot to run normally but it can't because azure can't detect the async function for some reason. Any help is appreciated
The OAuthHelpers class requires 'simple-graph-client' which houses all of the methods you are looking to utilize. In the original sample your code draws from, BotBuilder-Sample 24.bot-authentication-msgraph, if you navigate to the simple-graph-client.js file, you will see the methods called (i.e. sendMail, getRecentMail, getMe, and getManager) in the OAuthHelpers.js file.
If you haven't already, you will need to include a method for creating an event. This, in turn is called from the OAuthHelpers.js file as part of the bot dialog.
It's hard to know what is what without more code, but my guess is the token is being passed into your createevent method but, as the method (likely) doesn't exist as a graph api call, it doesn't know what to do with it.
Check out the following links for guidance:
MS Graph sample showing a GET call for top 3 calendar events
MS Graph unit test example, but demonstrates an event POST
API reference for creating an event
Add'l info on creating recurring events...might prove useful
Hope of help!
Related
I'm working on converting some existing bots to skills so that we can create a Skill Host bot that can call multiple "child bots". I used the skills-simple-bot-to-bot sample, and it kind of works. I can call the skill bot from the host and it works...for a single turn. But the host is creating a new conversation ID every turn, clearing the conversation state which makes my multi-turn waterfall dialogs not work. It is also causing any other values stored in conversation state to be cleared (e.g. I capture email address in conversation state so I don't have to reprompt it). The skill bot works fine when invoked directly (i.e. not through the skill host), so it's definitely something with the way the skill host works. I found this issue on GitHub which seems to be the same thing (that's for .NET but there are links to the other SDKs including js), though it seems to have been resolved years ago yet I'm still having the issue so I'm not sure it's the same.
So in short, how do I set up the skill host so that it doesn't generate new conversation IDs every turn?
Not sure this will help as it's almost exactly the same as the sample, but here's a snippet of the code where it appears conversation ID is being generated by the host. It seems maybe I need some way to NOT call createSkillConversationIdWithOptions, but if that's what is required I'm not sure what I need to do to generate the skillConversationId other than what is currently in the sample.
async sendToSkill(context, targetSkill) {
// NOTE: Always SaveChanges() before calling a skill so that any activity generated by the skill
// will have access to current accurate state.
await this.conversationState.saveChanges(context, true);
// Create a conversationId to interact with the skill and send the activity
const skillConversationId = await this.conversationIdFactory.createSkillConversationIdWithOptions({
fromBotOAuthScope: context.turnState.get(context.adapter.OAuthScopeKey),
fromBotId: this.botId,
activity: context.activity,
botFrameworkSkill: this.targetSkill
});
// route the activity to the skill
const response = await this.skillClient.postActivity(this.botId, targetSkill.appId, targetSkill.skillEndpoint, this.skillsConfig.skillHostEndpoint, skillConversationId, context.activity);
// Check response status
if (!(response.status >= 200 && response.status <= 299)) {
throw new Error(`[RootBot]: Error invoking the skill id: "${ targetSkill.id }" at "${ targetSkill.skillEndpoint }" (status is ${ response.status }). \r\n ${ JSON.stringify(response.body) }`);
}
}
i am using the microsoft bot sdk in combination with an restify server (In package.json: "botbuilder": "^4.11.0"). I start a waterfall dialog that triggers a long running API. I save the the conversation reference and the id of the sent message to create an reply after the API call is completed:
replyToId = (await stepContext.context.sendActivity({ attachments: [ac]})).id; (in Dialog)
this.conversationReference = TurnContext.getConversationReference(context.activity); (in bot.ts)
After the completion of the API call, I want to create a reply to the last message of the dialog:
await this.adapter.continueConversation(this.conversationReference, async turnContext => {
await turnContext.sendActivity(newMessage);
});
newMessage is the Activity-object that contains further information for the user about the result of the API call.
The problem is that newMessage is not displayed as an reply to the existing message but as a separate message, although newMessage.replyToId is set to this.replyToId:
Additional information: Both messages, the last of the dialog and the "reply" are adaptive cards, but it does not make a difference if I send just simple text, same behaviour.
Would be grateful for any help :)
Instead of using "replyToId", put the id of the message you want to reply to, at the end of the conversation reference. As an example, if your conversationReference has a conversationId of 19:ac....cf#thread.skype, change it to: 19:ac...cf#thread.skype;messageid=12345678, where 12345678 is what you are currently using for "replyToId"
I'm using the Microsoft bot-framework to create a bot and integrate it into teams.
Part of the bot's requirements include proactively messaging users once per day. From what I understand, I can only message users that has been added to the team/groupChat after the bot, or that have messaged the bot directly.
My question is - can I somehow bypass this limitation?
A friend of my referred me to a new feature of graphAPI, as part of the new beta version - https://learn.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http.
To me it doesn't seem like it could be related to the solution since I'm not getting any data back in the response, so if I have no conversationReference object I still can't message the user.
At the moment my solution is to simply broadcast a message in the channel when it's added, asking users to "register" with it by messaging it. Anyone has any other suggestion?
The easiest way is to:
Install the bot for the team
Query the Team Roster -- The link in Step 3 has an alternative way to do this towards the bottom
Create a conversation with the user and send a proactive message
There's a lot of code in those links and it's better to just visit them than to copy/paste it here.
The end of Step 3 also mentions trustServiceUrl, which you may find handy if you run into permissions/auth issues when trying to send a proactive message.
Edit for Node:
Install Necessary Packages
npm i -S npm install botbuilder-teams#4.0.0-beta1 botframework-connector
Note: The #<version> is important!
Prepare the Adapter
In index.js
const teams = require('botbuilder-teams');
adapter.use(new teams.TeamsMiddleware());
Get the Roster
// Get Team Roster
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(context.activity.conversation.id);
Send the Proactive Message
const { TeamsContext } = require('botbuilder-teams');
// Send Proactive Message
const teamsCtx = TeamsContext.from(context);
const parameters = {
members: [
roster[0] // Replace with appropriate user
],
channelData: {
tenant: {
id: teamsCtx.tenant.id
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
Trust the ServiceUrl, as Necessary
Read about it. You'd want this before the message is sent.
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
EDIT: The Graph API you've referenced is only necessary if you wish to proactively message a user who is not in a channel/groupChat where the bot is installed. If you need to proactively message only people who are in context where the bot is installed already, the answer from mdrichardson is the easiest possible method.
We've identified a couple of issues with the Graph API beta endpoint you referenced that should be fixed in the near term. In the meantime workarounds are as follows:
Calling:
POST https://graph.microsoft.com/beta/me/teamwork/installedApps/
{"teamsapp#odata.bind":"https://graph.microsoft.com/beta/appcatalogs/teamsapps/APP-GUID"}
Will install an app in the personal scope of a user.
Known issue: Currently, if the app contains a bot, then installation will not lead to creation of thread between the bot and the user. However to ensure that any missing chat threads, get created, call:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Calling:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Gets the chat between a user and an app containing a bot.
Known issue: Calling this API will lead to sending a conversation update event to the bot even though there were no updates to the conversation. Your bot will essentially get two install events and you'll need to make sure you don't send the welcome message twice.
We'll also be adding more detailed documentation for the proactive messaging flow using these Graph APIs
I have used pusher recently in my PHP laravel project and it is working fine.
What I know about pusher is that it is a real time layer between our server and client and creates web socket connection to our client browser.
I setup pusher in my application using below tutorial:
pusher integration with laravel
What I have created using pusher for my web application:
1.I have created a notification functionality. Where when one user add some data to database say when one user starts following other user a event is triggered and that event sends data to particulr channel say 'notification-channel' and in my js code I have subscribed to this channel. For that I have written below line of codes:
//instantiate a Pusher object with our Credential's key
var pusher = new Pusher('68fd8888888888ee72c', {
encrypted: true
});
//Subscribe to the channel we specified in our Laravel Event
var channel = pusher.subscribe('notification-channel');
//Bind a function to a Event (the full Laravel class)
channel.bind('App\\Events\\HelloPusherEvent', addMessage);
By using addMessage() function I display some data. Now I have put a check on client side so that only if logged in user is intended to receive this message by writing simple if condition. As I have sent intended user's id in within data from App\Events\HelloPusherEvent so I used this Id to display msg to specific users only.
But I think this is not right approach to use pusher for notifications or any other functionality. Further in my project I want to use pusher for displaying new news feeds on user's newsfeed without page refresh, where obviously few users will see those posts according to whom is posting that news post.
But How I will user pusher in a way that I don't need to implement if conditions on client side to stop displaying data.
Here my concern is that if I will keep sending data to all the active clients and put if conditions to filter data that will ultimately degrade my application.
My concerns:
If pusher sends data to multiple clients that is obviously all the active users then will it not cause overhead.
Is there any option to use channels to channelize data to intended users only.
As I am implementing pusher first time I have few doubts regarding its actual working so is there any blog which can help me to understand its real time working.
Let me know if my question is not clear and specific enough, I will elaborate it further.
Thanks in advance to all who will try to answer.
This Question pusher-app-client-events explained that we can create different channels for different users to send msg to only intended users.
I go through this FAQ and came to know that we can create unlimited channels for one registered APP.
Creating multiple channels won't cause any overhead.
Now if I want to send notification to user 1 then I would create a channel 'notificaton-channel-1' and would subscribe user 1 to same channel within my frontend code.
The event class that I am using within my PHP laravel project looks like below:
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
/**
* Just implement the ShouldBroadcast interface and Laravel will automatically
* send it to Pusher once we fire it
**/
class HelloPusherEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
/**
* Only (!) Public members will be serialized to JSON and sent to Pusher
**/
public $message;
public $id;
public $for_user_id;
/**
* Create a new event instance.
* #param string $message (notification description)
* #param integer $id (notification id)
* #param integer $for_user_id (receiver's id)
* #author hkaur5
* #return void
*/
public function __construct($message,$id, $for_user_id)
{
$this->message = $message;
$this->id = $id;
$this->for_user_id = $for_user_id;
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
//We have created names of channel on basis of user's id who
//will receive data from this class.
//See frontend pusher code to see how we have used this channel
//for intended user.
return ['notification-channel_'.$this->for_user_id];
}
}
and on Frontend I subscribed to 'notification-channel-'+logged_in_user_id
//Subscribe to the channel we specified in our Laravel Event
//Subscribe user to the channel created for this user.
//For example if user's id is 1 then bind to notification-channel_1
var channel = pusher.subscribe('notification-channel_'+$('#logged_in_userId').val());
//Bind a function to a Event (the full Laravel class)
channel.bind('App\\Events\\HelloPusherEvent', addMessage);
This way we can send data to intended users only rather blocking data received by all the users by putting conditions in our client side code.
I think you should add User ID within Blade template directly, not using a form field:
var channel = pusher.subscribe('notification-channel_{{ Auth::id() }}');
I have created a c# based web hook in an azure function app, based on Adrian Halls excellent book on github.io
The web hook and app is running successfully when tested in portal.
When i call the webhook from my controller i can see i have the correct parameters and uri. But for some reason my function app never enters my method and give me an error saying:
The 'code' query parameter provided in the HTTP request did not match the expected value
My problem is that i do have my code query parameter in the request.
Basically i just want to trigger the webhook when a new todoitem is inserted in my database.
Anybody know what could be the problem?
Code:
Call from api controller to webhook method in backend
// POST tables/TodoItem
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
Webhook.SendAsync<TodoItem>(new Uri(WebhookUri), current);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
Webhook method in backend
public static async Task<HttpStatusCode> SendAsync<T>(Uri uri, T data)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = uri;
var response = await httpClient.PostAsJsonAsync<T>("",data);
return response.StatusCode;
}
Function in azure
#r "Newtonsoft.Json"
using System;
using System.Net;
using Newtonsoft.Json;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("Webhook triggered");
string jsonContent = await req.Content.ReadAsStringAsync();
dynamic data = JsonConvert.DeserializeObject(jsonContent);
log.Info($"Created New Todo ({data.Text}, {data.Complete})");
return req.CreateResponse(HttpStatusCode.OK);
}
Had the same issue today. Go to the Manage panel of your Azure Function. There you can copy the "default" key which works
Anders,
There are indeed some issues with the key management UI on the portal and those are being addressed (you can track one that was likely impacting you here
A workaround, at the moment, is to make sure you're using the appropriate key by opening the "keys" panel for the function and selecting the "default" function key, using that as the code.
There is also an API you can use to request the keys directly from the runtime, here's an example of invoking that API to retrieve the keys for a given function:
https://<functionappname>.azurewebsites.net/admin/functions/<functionname>/keys?code=<your admin key>
This must be a bug in azure functions app.
I created a couple of web hook functions more to see if i could hit one of those.
No success same error as before.
But then i went back to my old function and suddenly it worked. I don't know why one of my new web hooks i tested on is a copy of the old one and it is still not working. Maybe an azure functions expert know more about this.