Discord C# Bot - Delete the latest message - c#

I am using the rogue exception package for my discord bot.
When a user calls the bot by a command, I want the bot delete his message before executing the command.
So in my "MessageReceived"-Event i have this code so far:
private async Task MessageReceived(SocketMessage s)
{
var msg = s as SocketUserMessage; // the input
if (msg == null || !msg.Content.StartsWith("!") || msg.Author.IsBot) // return if null, msg is no command, msg is written by the bot
return;
if (msg.Channel is SocketGuildChannel guildChannel) // just delete the command if the msg is written in the guild channel, not a private message channel
await ??? // Delete the command
}
So does someone know, what to write there =?

I can see that you are using Discord.NET API for your bot.
So from this documentation here.
Take a look at the Method list in the properties of SocketMessage. (By the way, take a look at the right side of the webpage, you should be able to see a bar that allows you to navigate easily)
In case you are wondering why we are looking at SocketMessage, that is because your delegate will run whenever a user posts a message, and that message is your SocketMessage, hence that is what you would want to delete.
You should be able to see a method called: DeleteAsync. That would be what you want.
(Screenshot is below)
For the arguments, you can see that its a RequestOption datatype and by default it has been set null for you. You can change that, but I highly recommend using the default.
Also a good thing to take note that is the bot will do nothing (and return an exception) if it does not have the permission to manage messages.

Example:
(sorry, but some of the code strings are in Portuguese... this is a voting system)
[Command("Votar")]
[Summary("Abro uma votação, com opções de Sim e Não.")]
[RequireBotPermission(ChannelPermission.AddReactions)]
public async Task NovoVoto([Remainder] string secondPart)
{
Log.CMDLog(Context.User.Username, "Votar", Context.Guild.Name);
if (secondPart.Length >= 200)
{
await Context.Channel.SendMessageAsync("Perdão, porém seu voto não deve ter mais de 200 caracteres");
return;
}
var embed = new EmbedBuilder();
embed.WithColor(new Color(126, 211, 33));
embed.WithTitle("VOTE AQUI!");
embed.WithDescription(secondPart);
embed.WithFooter($"Votação criada por: {Context.User.Username}");
RestUserMessage msg = await Context.Channel.SendMessageAsync("", embed: embed);
await msg.AddReactionAsync(new Emoji("✅"));
await msg.AddReactionAsync(new Emoji("❌"));
//Delete the command message from the user
await Context.Message.DeleteAsync();
}

Related

How to Greet new user in a QnA maker Bot?

I have created a QnA maker Bot. Now I would like to wish the user with a greeting when the conversation starts. I saw in a link that this can be achieved using Conversation update, I have added the following code in QnABot.cs which comes inside the Bots folder
private async Task HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
if (message.MembersAdded.Any(o => o.Id == message.Recipient.Id))
{
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl));
var reply = message.CreateReply();
reply.Text = "Hello and Welcome ";
await client.Conversations.ReplyToActivityAsync(reply);
}
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
}
Is this right place to add this code ?
I dont have a messagecontroller class, I only have BotController.cs should I add it there ?
Can I test this greeting in Bot Emulator or Should I try it in webchat itself ?
My requirement is to greet the user in the Directline Webchat.
Yes using the ConversationUpdate Activity Type will achieve what you need, you will be able to greet the user as soon as they join the conversation in the Emulator and the same should work fine for WebChat.
If you are using the 11.qnamaker sample then yes, you can handle those type of activities inside QnABot.cs

botFramework v4 how to handle dialog response after LUIS call

I have a bot written in C# that is using LUIS to determine intents. I have a method that makes a call to the LUIS service and then looks for an 'Open_Case' intent. The model has a CaseNumber entity defined which may or may not be included in the response from the LUIS service.
If the response doesn't have a case number entity I start a dialog to ask the user for the case number.
Once I have a case number I then want to return a card with case information.
Here's the code I have:-
/// <summary>
/// Dispatches the turn to the requested LUIS model.
/// </summary>
private async Task DispatchToLuisModelAsync(ITurnContext context, string appName, DialogContext dc, CancellationToken cancellationToken =
default (CancellationToken)) {
var result = await botServices.LuisServices[appName].RecognizeAsync(context, cancellationToken);
var intent = result.Intents ? .FirstOrDefault();
string caseNumber = null;
if (intent ? .Key == "Open_Case") {
if (!result.Entities.ContainsKey("Case_CaseNumber")) {
var dialogResult = await dc.BeginDialogAsync(CaseNumberDialogId, null, cancellationToken);
} else {
caseNumber = (string)((Newtonsoft.Json.Linq.JValue) result.Entities["Case_CaseNumber"].First).Value;
var cardAttachment = botServices.CaseInfoServices.LookupCase(caseNumber);
var reply = context.Activity.CreateReply();
reply.Attachments = new List < Attachment > () {
cardAttachment
};
await context.SendActivityAsync(reply, cancellationToken);
}
}
}
What I'm struggling with is where the code send the card response should sit.
In the code I currently have I send the card if the number was returned in the LUIS response, but if there was no number and I start the dialog then I only get access to the number either in the final step of the dialog or in the dialog result in the root turn handler. I've currently duplicated the reply inside the final step in the dialog, but it feels wrong and inelegant.
I'm sure there must be a way that I can collect the number from LUIS or the dialog and THEN send the response from a single place instead of duplicating code.
Any suggestions gratefully received...
I came to the conclusion that I need to put the code that displays the card into a method on the bot class, then call it from the else in code snippet and also from the turn handler when the dialogTurnStatus is equal to Complete

xUnit test async event handler

I have a class that uses Azure Service Bus and it basically sends an email by putting a message to a queue. When I write an integration tests I need to make sure I can receive the message that's been sent (no, I'm not testing Service Bus). So, here's the code for that:
[Fact]
public async Task PutEmailIntoTheQueue()
{
IlgQueueEmailInfo actual = new IlgQueueEmailInfo("from#address.com", "to#address.com", "subject", "test body", MessageBodyType.Text,
"email1#domain.com",
"email2#domain.com");
ServiceBusConnectionStringBuilder sbcb =
new ServiceBusConnectionStringBuilder(SERVICE_BUS_ENDPOINT_S, QUEUE_NAME_S, SAS_KEY_NAME, EMAIL_TESTS_SAS);
QueueClient receiveClient = new QueueClient(sbcb, ReceiveMode.ReceiveAndDelete);
bool hasBeenCalled = false;
//
// Check values here
//
async Task ReceiveMessageHandler(Message message, CancellationToken cancellationToken)
{
Output.WriteLine("Received Message\n");
Assert.True(message.Label != null && message.ContentType != null &&
message.Label.Equals(IlgEmailQueue.MESSAGE_LABEL_S, StringComparison.InvariantCultureIgnoreCase) &&
message.ContentType.Equals("application/json", StringComparison.InvariantCultureIgnoreCase));
byte[] body = message.Body;
string msgJson = Encoding.UTF8.GetString(body);
Output.WriteLine($"json: {msgJson}\n");
IlgQueueEmailInfo emailInfo = JsonConvert.DeserializeObject<IlgQueueEmailInfo>(msgJson);
Assert.NotNull(emailInfo);
Output.WriteLine("emailInfo is not NULL");
Assert.Equal(actual, emailInfo);
Output.WriteLine($"emailInfo equals to actual: {actual == emailInfo}\n");
Output.WriteLine("Setting hasBeenCalled to True");
hasBeenCalled = true;
await receiveClient.CompleteAsync(message.SystemProperties.LockToken);
}
receiveClient.RegisterMessageHandler(
ReceiveMessageHandler,
new MessageHandlerOptions(LogMessageHandlerException) {AutoComplete = true, MaxConcurrentCalls = 1});
await _emailQueue.QueueForSendAsync(actual.FromAddress, actual.ToAddresses[0], actual.Subj, actual.Body, MessageBodyType.Text, actual.CcAddress,
actual.BccAddress);
await Task.Delay(TimeSpan.FromSeconds(5));
Assert.True(hasBeenCalled);
}
But when I run it I get an exception saying something like "There's no currently active test". What is the best way of dealing with this kind of tests?
You are testing Azure Service Bus in a way that you're sending a message on er the wire and receive it. Looking at the code, you want to verify message is contracted in a certain way. Rather than going through the whole send / receive phase, you could short-circuit it by just testing the Message constructed by your code. Alternatively, create a plugin to intercept the message just before it's sent. In case you insist on sending/receiving, your code must not exist until assertion is either executed or there's a timeout. And that's due to the fact that message handler is a synchronous API that will continue execution of the test method before the message has a change to be processed by the callback. await Task.Delay(TimeSpan.FromSeconds(5)) is not guaranteed to be sufficient.

Discord.Net 1.0 How to use ModifyAsync/How to modify contents of a message

I'm trying to edit a message that my bot sent, but I can't seem to find any answers by myself. For context, the old message is a "waiting" message until the API I'm using retrieves the data I want. The new message is what the data that was received.
This is my current solution:
var msg = await ReplyAsync("old message");
//... unrelated code ...
await msg.DeleteAsync();
await ReplyAsync("new message");
The arguments for ModifyAsync(); are Action<MessageProperties> funct, [RequestOptions options].
I've attempted to use ModifyAsync(); myself, to no avail.
All I want to do is modify the content of the message, and all of the research I've done leads to earlier versions of the Discord.Net library.
How can I do this correctly?
I did some research and found this : https://github.com/RogueException/Discord.Net/issues/474
I know it isn't modifying a message but it works the same way, you pass it a lambda expression:
var Message = await Context.Channel.SendMessageAsync("test message");
await Message.ModifyAsync(msg => msg.Content = "test [edited]");
await Context.Channel.SendMessageAsync("Test.");
await Context.Message.ModifyAsync(m => { m.Content = "Test [Edited]."; });
I hope that helps

ActivityTypes.Typing clause gets executed in chatbot framework

I am developing a chatbot using MicrofsoftBotFramework on c#.net and LUIS cognitive services.
I just want to know when ActivityTypes.Typing clause gets executed in below code , I want to see in my botemulator as "you are typing" when actually user is typing.
private async Task HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl));
var reply = message.CreateReply();
reply.Text = "Hello user how are you?"
await client.Conversations.ReplyToActivityAsync(reply);
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
else if (message.Type == ActivityTypes.Ping)
{
}
}
Thanks
From the C# Bot Builder SDK Reference:
Typing is an indicator of activity on the other side of the
conversation. Generally it's used by Bots to cover "dead air" while
the bot is fulfilling a request of some sort. The Bot may also receive
Typing messages from the user, for whatever purposes it might find
useful.
You can access that reference page here.
I hope this helps!

Categories

Resources