My slack application currently sends buttons attached with messages. Whenever a button is clicked, it sends a post request. If the button's attached value is true, it saves a value to the database.
How the button should work is that when it's first clicked by any user, it replies with a Ok status and a message saying "Correct", anything subsequently will say "question has already been answered".
The problem i come across is that if multiple people click the button where it's attached value is set to true roughly at the same time. It'll all respons with "Correct". May I ask how should i be responding to the post request and how should i be inserting into the database sequentially so that only one correct is sent.
Current code
public async Task<ActionResult> Post()
{
var payload = Request.Form.FirstOrDefault(x => x.Key == "payload");
bool value= JsonConvert.DeserializeObject<RootObject>(payload.Value);
using (var contexts = new TriviaBotDbContextFactory().CreateDbContext(null))
{
if (value)
{
// return if
var item = contexts.Questions.Include(x => x.Guesses).First(x => x.Id == question.Id);
if (item.Guesses.Any(y => y.Correct))
return StatusCode(200);
// Send Message Code
SBMClient client = new SBMClient(webHook);
Message msg = new Message("Correct");
client.Send(msg);
// Save to database
item.Guesses.Add(new Answer
{
Correct = true,
User = button.user.name
});
await contexts.SaveChangesAsync();
}
}
return StatusCode(200);
}
Related
I'm trying to get the payment status of a payment. I've got the code below:
public bool HasBeenPayed(string transactionKey)
{
var logger = new CustomLogger();
var client = new SdkClient(() => logger);
var request = client.CreateRequest().
Authenticate(
_websiteKey,
_apiKey,
_isLive,
CultureInfo.GetCultureInfo("nl-nl"),
BuckarooSdk.DataTypes.ChannelEnum.Web).
TransactionStatusRequest().
Status(transactionKey);
var status = request.GetSingleStatus();
var statusCode = status.Status.Code.Code;
return statusCode == BuckarooSdk.Constants.Status.Success;
}
When I execute this, it freezes on executing request.GetSingleStatus();. It does not continue to the next line. The last thing logged in the custom CustomLogger is:
The serialized request in JSON format is: null
The documentation is limited, so I haven't found the answer there. There are not many Buckaroo posts on Stack Overflow either.
How do I get the status of a Buckaroo payment using the BuckarooSdk?
I am using botframework 3.9 and for some reasons I can't upgrade now. I would like to know if there is a way to open a new browser window where I can render a page or fire a JavaScript function. Here is how I am opening link:
await context.PostAsync(#"please [click here](http://www.example.com/)");
This does renders the link however, I wanna open a link in JavaScript window so I can close the window programmatically or if possible if I can fire some JavaScript function.
This is actually much easier than you think. If you have a look at the WebChat README you can see there are many ways WebChat can be customized. Pay particular attention to sample 11, which you can demo here. The body of that page looks like this:
<div id="webchat" role="main"></div>
<script>
(async function () {
// In this demo, we are using Direct Line token from MockBot.
// To talk to your bot, you should use the token exchanged using your Direct Line secret.
// You should never put the Direct Line secret in the browser or client app.
// https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
// We are creating our own version of Redux store, which include middleware and optional initial state.
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// After connected, we will send a message by dispatching a Redux action.
dispatch({ type: 'WEB_CHAT/SEND_MESSAGE', payload: { text: 'sample:backchannel' } });
} else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
// When receiving an activity of type "event" with name of "sample:backchannel", prompt it out.
const { activity } = action.payload;
if (activity.type === 'event' && activity.name === 'sample:backchannel') {
alert(JSON.stringify(activity, null, 2));
}
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
// We will use a custom version of Redux store, which we added middleware to handle backchannel messages.
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
You can see in this sample that WebChat has been modified to respond to certain activities from the bot by opening a popup window using JavaScript's alert function. The modification is done by creating a store and then passing that store as an argument to renderWebChat.
Rather than opening an alert window, you want to open a window you can close. This could be achieved if you modify the store to look like this:
let windows = {};
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.type === 'event') {
let url = activity.value;
if (activity.name == 'open' && !windows[url]) {
windows[url] = window.open(url);
}
if (activity.name == 'close' && windows[url]) {
windows[url].close();
windows[url] = null;
}
}
}
return next(action);
}
);
You don't have to implement it this way, but I've implemented it so that when WebChat receives an event activity named open it will open a window and when it receives an event activity named close it will close a window. It even keeps track of multiple windows so you can choose which window to close.
I've set up a bot that sends open and close events when the user types "open [url]" or "close [url]". The bot code looks like this:
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var text = activity.Text;
var words = text.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
var firstWord = words.FirstOrDefault().ToLower();
var secondWord = words.Length > 1 ? words[1] : "https://stackoverflow.com/";
Activity reply = null;
switch (firstWord)
{
case "open":
case "close":
reply = activity.CreateReply();
reply.Type = ActivityTypes.Event;
reply.Name = firstWord;
reply.Value = secondWord;
break;
default:
reply = activity.CreateReply("Try \"open ...\" or \"close ...\"");
break;
}
await connector.Conversations.SendToConversationAsync(reply);
Hopefully you can use this information and modify it to suit your needs.
Has something changed with Cortana in the last few days?
I have buttons on an adaptive card which now do nothing. I have remote debugged and hit all breakpoints as expected but when tapping on a button nothing happens. It is as though the buttons are disabled somehow.
Everything works fine in the emulator.
My Bot code simply shows buttons in an adaptive card which then post their DataJson value which is received by the MessageReceivedAsync method.
I have been refining how this all works as I found that Cortana has a limit of 5 actions on one card. I did a bit of a work around in this and make each button appear on a card.
Therefore, I have been thinking that in my refining, I have done something to make these buttons no longer work.
However, I have now put my code back to how it was days ago which definitely did work in Cortana and it now does not work.
My question therefore is, has anything changed in the Cortana side to stop this?
Thanks!
I modified the echodemo to put up a simple adaptive card and it worked as documented: "Thanks for Clicking! SomeType is SomeData". (I am logging a ticket to update documentation to v1.0.3 of adaptive cards).
public async Task ClickHandleAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
try
{
string someValue = "unknown";
if (message.Value != null)
{
// Got an Action Submit
dynamic value = message.Value;
string s = value.ToString();
Trace.WriteLine(s);
someValue = value.SomeType;
}
else
Trace.TraceInformation("There is no value");
//string data = message.ChannelData.ToString();
//Trace.WriteLine(data);
//Trace.TraceInformation("stringify message");
//string json = new JavaScriptSerializer().Serialize(message);
//Trace.WriteLine(json);
await context.PostAsync("Thanks for the click! SomeType is " + someValue);
context.Wait(MessageReceivedAsync);
}
catch (Exception e)
{
Trace.TraceInformation(e.ToString());
}
}
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (message.Text == "show card")
{
var response = context.MakeMessage();
if (response.Attachments == null)
response.Attachments = new List<Attachment>();
AdaptiveCard card = new AdaptiveCard();
card.Body.Add(new AdaptiveTextBlock()
{
Text = "This is a test",
Weight = AdaptiveTextWeight.Bolder,
Size = AdaptiveTextSize.Medium
});
card.Actions.Add(new AdaptiveSubmitAction()
{
Title = "Click Me",
Id = "12345678",
DataJson = "{ \"SomeType\": \"SomeData\" }"
});
Attachment attachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = card,
Name = "MyCard"
};
response.Attachments.Add(attachment);
await context.PostAsync(response);
context.Wait(ClickHandleAsync);
}
Scenario:
I send request to server queue (I'm using RabbintMQ to asynchronously process message). When the server processes the request it produces two responses to different queues.
I would like to use RX to subscribe to to responses, but also have access to their corresponding requests.
What I have so far:
I use EventAggregator that uses reactive extension and exposes IObservable for event stream:
public interface IEventAggregator
{
void Publish<TEvent>(TEvent sampleEvent);
IObservable<TEvent> GetEvent<TEvent>();
}
When I send request I publish an event:
eventAggregator.Publish(new RequestSent { ID = Guid.NewGuid(), ... })
//I could later subscribe to the event like this:
//eventAggregator.GetEvent<RequestSent>().Subscribe(..)
When server responds, the responses are also published to the EventAggregator, so I can subscribe to them:
eventAggregator.GetEvent<ResponseFromQueue1>().Subscribe(OnResponseFromQueue1)
eventAggregator.GetEvent<ResponseFromQueue2>().Subscribe(OnResponseFromQueue2)
I could also subscribe to RequestSent
What I need:
private void OnResponseFromQueue1(RequestSent request, ResponseFromQueue1 response)
{
I need access to both request and respone
}
and this would be even better:
private void OnResponse(
RequestSent request,
ResponseFromQueue1 response1,
ResponseFromQueue2 response2)
{
//actually, this would simplify implementation of my logic a lot
}
Is is possible using RX?
You could use SelectMany, assuming you can use something like the ID to associate the request with the responses
trigger.SelectMany(requestData => {
//We need to share this
var id = Guid.NewGuid();
//Publish your event
eventAggregator.Publish(new Request { ID = id, /*...*/ });
//Start listening for the two responses
//Grab only the first item matching the IDs
var left = eventAggregator.GetEvent<ResponseFromQueue1>().First(res => res.ID == id);
var right = eventAggregator.GetEvent<ResponseFromQueue2>().First(res => res.Id == id);
//We are done once both values have emitted.
return left.Zip(right);
}, (request, responses) => {
/*Here you will have access to the request and an array of the responses*/
});
One thing to bear in mind is that this code right now is assuming that Publish will return before the responses come back. Since you said this is RabbitMQ that is probably a safe assumption, but something to bear in mind if you do any unit testing with this.
Edit
It seems in your scenario you actually would have:
//Set up the queue first
eventAggregator.GetEvent<RequestSent>()
.SelectMany(requestSent => {
var id = requestSent.ID;
var left = eventAggregator.GetEvent<ResponseFromQueue1>().First(res => res.ID == id);
var right = eventAggregator.GetEvent<ResponseFromQueue2>().First(res => res.ID == id);
return left.Zip(right);
}, (request, response) => {/**/});
//...Sometime later
eventAggregator.Publish(new Request{});
I am using rabbit-Mq in my web app(Asp.net-MVC 4.0). My requirement is to send a message to a particular user. Suppose if user1 is online and he sends a message to user2 by rabbit-Mq. It should be received by "user2" only. The code I have used is a template which stores the message in the queue and whenever the user clicks on receive he will get that message but there is no restriction of particular user in my case. Anyone can get that message which is wrong and I have to handle that. Please help me regarding this.
Do we have something in rabbit-Mq that can distinguish the correct message to correct user/Consumer? Can we set a key with message and check the key while receiving?
Is this possible?
Below I am writing the code I am using to send and receive the messages
public ActionResult SendMessage(MessagingModel ObjModel)
{ var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
Message = ObjModel.Message;
channel.QueueDeclare("MessageQueue", true, false, false, null);
var body = Encoding.UTF8.GetBytes(ObjModel.Message);
channel.BasicPublish("", "MessageQueue", null, body);
}
}
}
public JsonResult RecieveMessage()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("MessageQueue", true, false, false, null);
bool noAck = true;
BasicGetResult result = channel.BasicGet("MessageQueue", noAck);
if (result == null)
{
Message = "No Messages Found.";
}
else
{
IBasicProperties props = result.BasicProperties;
byte[] Body = result.Body;
Message = Encoding.Default.GetString(Body);
}
}
}
First, you must remember the following things:
All messages in RabbitMQ published through exchanges.
Queues binded to exchanges.
Event if you publish message directly into queue, actually it still passes through the default exchange - (AMPQ default).
There are different kinds of exchanges. You can read a bit about exchanges here: https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html
In you case you might consider use a topic or headers exchanges, but in this case you should for each user
have a queue, and if the number of users in the system is large, then it will be very resource intensive.
Also you can add specific header to you message:
var props = model.CreateBasicProperties();
props.Headers.Add("UserId", userId);
and then in RecieveMessage() method after read message from queue see this header and if message intended for current user - receive it and acknowledge this message, otherwise
not acknowledge this message.
But this is bad solution. I would just kept messages from the queue to the database, and then read them out filtering by user.