I need to proactivly create conversation on channel in msteams. So i looked for examples but didn't find any examples of realy proactive conversation creation. All examples include first of all handling message, and creating conversation using context.
To be more accurate i have facebook, whatsapp, and web widget. Users write for example from facebook, i get message through fb webhook and i need to create new thread ( block with replies inside channel ) and only after that, someone who will answer in channel using thread block and i'll get message.
As i understood i need to bootstrap conversation object and use adapter.createConversation({ ...convFields }), but for example i don't have serviceUrl.
// i am using adapter from examples
new BotFrameworkAdapter({
appId: id,
appPassword: password
});
// then i have something like that in examples
const conversationParameters = {
isGroup: true,
channelData: {
channel: {
id: 'msteams'
}
},
activity: 'dsada'
};
const connectorClient = this.adapter.createConnectorClient(
context.activity.serviceUrl // i don't have context to get that serviceUrl, because i must do it first, not handle message and create thread after that.
);
const conversationResourceResponse = await connectorClient.conversations.createConversation(
conversationParameters as any
);
const conversationReference = TurnContext.getConversationReference(
context.activity // same here, i don't have context
);
conversationReference.conversation.id = conversationResourceResponse.id;
return [conversationReference, conversationResourceResponse.activityId];
In order to prevent (or at least hinder) spam, your bot can only send proactive messages to channels or group chats where it is already installed. In that instance you'll need to store the necessary information from the conversationUpdate membersAdded event you'll receive.
For 1:1 chats, it is possible to create a new conversation with a user, however your bot needs to know the Id of the user in order to do so. Typically this is achieved by retrieving the roster of a group chat or team where your bot is installed.
Essentially, it isn't possible to send a completely proactive message - the bot needs to be installed and/or have some amount of information about where it is sending the message previously.
Assuming you can achieve the correct permissions, it is possible to proactively install your bot. See this article for more details on that approach: https://learn.microsoft.com/en-us/graph/teams-proactive-messaging
Even though it is in C#, you may find this sample helpful as it demonstrates the minimal amount of information required in order to send proactive messages to each type of destination (which is the same across languages): https://github.com/clearab/teamsProactiveMessaging.
The relevant file is below:
public class MessageSender : IMessageSender
{
private ConnectorClient conClient;
private string serviceUrl;
public MessageSender(string serviceUrl, string id, string password)
{
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl);
conClient = new ConnectorClient(new Uri(serviceUrl), id, password);
}
public async Task<ResourceResponse> SendOneToOneMessage(string conversationId, Activity activity)
{
return await conClient.Conversations.SendToConversationAsync(conversationId, activity);
}
public async Task<ConversationResourceResponse> CreateOneToOneConversation(string userId, string tenantId)
{
var members = new List<ChannelAccount>()
{
new ChannelAccount
{
Id = userId
}
};
ConversationParameters conParams = new ConversationParameters
{
Members = members,
TenantId = tenantId
};
return await this.conClient.Conversations.CreateConversationAsync(conParams);
}
public async Task<ConversationResourceResponse> CreateAndSendChannelMessage(string channelId, Activity activity)
{
ConversationParameters conParams = new ConversationParameters
{
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(channelId)
},
Activity = activity
};
ConversationResourceResponse response = await this.conClient.Conversations.CreateConversationAsync(conParams);
return response;
}
public async Task<ResourceResponse> SendReplyToConversationThread(string threadId, Activity activity)
{
return await this.conClient.Conversations.SendToConversationAsync(threadId, activity);
}
}
Related
I would like to make a discord bot that creates an issue based on user input from discord. Any idea how I would do this? I am using JavaScript and would like to integrate it into an existing bot. Thanks!
You can take ideas from the LeagueSandbox/IssueBot (Typescript), which does create issues.
It does use npmjs.com/package/github-api, from github-tools/github
export class IssueCommand extends Command {
execute() {
if(!this.args) {
return
}
let issueBody = ISSUE_TEMPLATE
.replace("{PLACEHOLDER}", this.args[2] || "_No content_")
.replace("{CHANNEL}", this.message.channel.name)
.replace("{USER}", this.message.author.username)
Bot.gitHub.api.issues.create({
owner: config.githubName,
repo: this.args[0],
title: this.args[1],
body: <any>issueBody // Typings for the `github` package are incorrect, so we have to cast to any here.
},
(error, response) => this.handleGithubResponse(error, response)
)
}
handleGithubResponse(error, response) {
if(error) {
let formattedError = JSON.stringify(error, null, 4)
let reply = ERROR_TEMPLATE.replace('{PLACEHOLDER}', formattedError)
this.message.reply(reply)
return
}
let reply = SUCCESS_TEMPLATE.replace('{PLACEHOLDER}', response.html_url)
this.message.reply(reply)
}
}
You have to set up that bot in your Discord application.
Maybe see the GitHub API docs for Creating Issues
You might need to create an app for it.
I am using a bot framework with direct line, and I would like to intercept the user's message before sending it to the server to modify it.
The idea is that if the user enters some phone number, credit card, etc, modify that part of the message by asterisks for example, and that does not travel the message with that data to the server.
I have tried to configure some event or activity but I can not do it.
I have tried using javascript, create an addeventlistener to the inputBox and the button, but when that event is launched the message can no longer be modified
any ideas?
conect.activity$
.filter(function (activity) {
return activity.type === 'endOfConversation';
})
.subscribe(function (activity) {
console.log('RemoveLocalStorage endOfConversation');
RemoveLocalStorage("paramCon");
});
BotChat.App({
botConnection : conect,
speechOptions: speechOptions,
user: user,
bot: bot,
typing:false,
locale: (params.locale !== undefined) ? params.locale : "es-es",
resize: 'detect'
},window.parent.frames["chatBot"].document.getElementById('bot'));
//window.frames[0].document.getElementById('bot')
//document.getElementById("bot")
window.parent.frames["chatBot"].document.getElementsByClassName("wc-send")[0].addEventListener("click", disableSensitiveData);
window.parent.frames["chatBot"].document.getElementsByClassName("wc-textbox")[0].addEventListener("keyup", disableSensitiveData);
You can create a custom middleware to intercept and modify the text attribute of messages when the user hits send. I created examples in V3 and V4 of Webchat below that convert the entire message to asterisks.
WebChat V4
// We are adding a new middleware to customize the behavior of WEB_CHAT/SEND_MESSAGE.
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'WEB_CHAT/SEND_MESSAGE') {
// Edit text when user sends message
action.payload.text = action.payload.text.split('').map(_ => '*').join('')
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
Checkout the WebChat Repository for more samples and information about v4.
WebChat V3
We are going to modify how the bot handles posting activities to intercept and modify the message from the user.
var dl = new BotChat.DirectLine({ secret: '<SECRET>' });
BotChat.App({
botConnection: Object.assign({}, dl, {
postActivity: activity => {
// Edit text when user sends message
activity.text = activity.text.split('').map(_ => '*').join('');
return dl.postActivity(activity);
}
}),
bot: 'bot',
user: 'user',
resize: 'detect',
}, document.getElementById('bot'));
Hope this helps!
I'm seeking some wisdom from the Angular community. I am working on a simple project using the MEAN stack. I have set up my back-end api and everything is working as expected. Using Postman, I observe expected behavior for both a GET and PUT routes to retrieve/update a single value - a high score - which is saved in it's own document in its own collection in a MongoDB. So far so good.
Where things go off track is when trying to access the PUT api endpoint from within Angular. Accessing the GET endpoint is no problem, and retrieving and displaying data works smoothly. However, after considerable reading and searching, I am stll unable to properly access the PUT endpoint and update the high score data when that event is triggered by gameplay. Below are the snippets of code that I believe to be relevant for reference.
BACK-END CODE:
SCHEMA:
const _scoreSchema = {
name: { type: String, required: true },
value: { type: Number, "default": 0 }
};
ROUTES:
router
.route('/api/score/:highScore')
.put(scoreController.setHighScore);
CONTROLLER:
static setHighScore(req, res) {
scoreDAO
.setHighScore(req.params.highScore)
.then(highScore => res.status(200).json(highScore))
.catch(error => res.status(400).json(error));
}
DAO:
scoreSchema.statics.setHighScore = (value) => {
return new Promise((resolve, reject) => {
score
.findOneAndUpdate(
{"name": "highScore"},
{$set: {"value": value} }
)
.exec(function(err, response) {
err ? reject(err)
: resolve(response);
});
});
}
ANGULAR CODE:
CONTROLLER:
private _updateHighScore(newHighScore): void {
console.log('score to be updated to:', newHighScore)
this._gameService
.updateHighScore(newHighScore);
}
SERVICE:
updateHighScore(newHighScore: Number): Observable<any> {
console.log(newHighScore);
let url = '/api/score/' + newHighScore;
let _scoreStringified = JSON.stringify({value: newHighScore});
let headers = new Headers();
headers.append("Content-Type", "application/json");
return this._http
.put(url , _scoreStringified, {headers})
.map((r) => r.json());
}
Note that the console.log(newHighScore) in the last block of code above correctly prints the value of the new high score to be updated, it's just not being written to the database.
The conceptual question with PUT routes in angular is this: If the api is already set up such that it receives all the information it needs to successfully update the database (via the route param) why is it required to supply all of this information again in the Angular .put() function? It seems like reinventing the wheel and not really utilizing the robust api endpoint that was already created. Said differently, before digging into the docs, I naively was expecting something like .put(url) to be all that was required to call the api, so what is the missing link in my logic?
Thanks!
I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.
I want to write a simple chat on meteor.js and thus I do not want to store the data in the database.
But I never found how to make an application without a database.
Here is an example of code as I can imagine.
Server code:
export let ws = [{_id:'1', text:'test1'}, {_id:'2', text:'test2'}];
Meteor.publish('ws', function wsPub() { return ws; });
let ctr = 3;
Meteor.methods({
'addMsg'(text) { ws.push({_id:ctr+1, text:text}); }
});
and client code:
import {ws} from '../api/model.js';
class Rtc extends Component {
constructor(props) {
super(props);
}
addMsg(e){
e.preventDefault();
Meteor.call('addMsg', this.refs.input.value);
}
render() {
return (
<div>
{this.props.ws.map((item, i)=>{
return(<span key={i._id}>{item.text}</span>);
})}
<input type="text" ref="input" />
<input type="submit" value="submit" onClick={this.addMsg.bind(this)}/>
</div>
);
}
}
export default createContainer( () => {
Meteor.subscribe('ws');
return { ws: ws };
}, Rtc);
but I do not understand what I wrote is not so in the createContainer?
UPD: I updated server code, but still websockets does not work:
Meteor.publish('ws', function wsPub() {
let self = this;
ws.forEach( (msg)=> {
self.added( "msg", msg._id, msg.text );
});
self.ready();
// return ws;
});
If you want to control what is sent over a publish, get a reference to the "publish instance" (really a specific client with a specific subscription) and use its add/change/remove commands:
let messages = [];
let clients = [];
Meteor.publish('ws', function() {
clients.push(this);
_.each(messages, (message) => {this.added('msg', message._id, message);});
this.ready();
});
Meteor.methods({
addMsg(text) {
let newMessage = {_id: Meteor.uuid(), text: text};
messages.push(newMessage);
_.each(clients, (client) => {client.added('msg', newMessage._id, newMessage);});
}
});
Regarding your code that you wrote in an update: you're sending a string where the function added expects a document (an object). Also, unlike this example above, you do not tell the clients when the ws (messages array) has changed.
I'd recommend also renaming these things to be more verbose and clear :)
What you suppose won't work. Because Meteor.publish returns a cursor to a Collection or array of Collections. According to the official documentation:
Publish functions can return a Collection.Cursor, in which case Meteor will publish that cursor’s documents to each subscribed client. You can also return an array of Collection.Cursors, in which case Meteor will publish all of the cursors.
Again, when you subscribe to a publication, it stores the data(as cursor to the same collection as the publication) locally in MiniMongo. So a chat without database is not technically possible with pub-sub in Meteor.