Purge command for a Discord bot in C# - c#

I'm not much of a coder or anything I'm just doing this for fun!
A server I am in with some friends needed a bot, there's of course a ton of bots available but I thought I'd go ahead and try my luck at making my own. I know some basic code and I've written a simple bot in C#, but for the life of me I cannot figure out how to make a purge command.
What I currently have created is this:
RegisterPurgeCommand();
private void RegisterPurgeCommand()
{
commands.CreateCommand("purge")
.Parameter("PurgeAmount")
.Do(async (e) =>
{
var messagesToDelete = await e.Channel.DownloadMessages(convert.ToInt32(e.GetArg("purgeAmount")));
await e.Channel.DeleteMessages(messagesToDelete);
await e.Channel.SendMessage(e.GetArg("purgeAmount") + "Messages Deleted.");
});
}
You can view the code here in screenshot format if you prefer
What I initially had was a purge command that deleted messages by x amount in the code, not by the amount I want. For example, what my goal is that in Discord I will do something along the lines of !purge 10 and the last 10 messages are deleted. What I previously had was a !purge command that deleted the previous 10 messages, but if I wanted to do 7 for example, it would still do 10.
The code for that, is:
RegisterPurgeCommand();
private void RegisterPurgeCommand()
{
commands.CreateCommand("purge")
.Do(async (e) =>
{
Message[] messagesToDelete;
messagesToDelete = await e.Channel.DownloadMessages(100);
await e.Channel.DeleteMessages(messagesToDelete);
});
}
you can view the code here in screenshot format if you prefer
this worked fine, but as I said wasn't really efficient.
Now, I'll be completely honest and say that the the method I'm using now (the one that isn't working) is off of an explanation on Gist.
So what it currently does is... Absolutely nothing.. What it used to do is delete x amount of messages that I told it to delete in the code so for example if I wanted to remove 7 messages in the server it would delete 10.
What I want it do is that I can tell the bot to remove x amount of messages in the server regardless by its amount, not that if I want to remove 7 that it removes 10.
Maybe I'm missing something very easily? Maybe I'm just overlooking something stupid? I am legit lost. It is also 6 in the morning as I'm writing this, so it may be that aswell.

You are parsing a Parameter PurgeAmount but not actually using it for anything.
messagesToDelete = await e.Channel.DownloadMessages(100);
On this line instead of using 100, use your purge amount parameter
EDIT with my version:
So this is how I did it, ignore the console stuff thats just debugging.
Console.WriteLine(_channel.Users);
var userPermissions = _user.GetPermissions(_channel).ManageMessages;
Console.WriteLine("Admin" + userPermissions);
int number = int.Parse(_parameter);
Message[] message = new Message[number];
message = _channel.DownloadMessages(number).Result;
if (userPermissions == true)
{
_channel.DeleteMessages(message);
Console.WriteLine("Channel Admin: " + _user + " deleted messages from the channel: " + _channel);
}
else
{
Console.WriteLine("User: " + _user + " tried to delete messages from: #" + _channel + " when they aren't an admin there.");
}

Related

Can we use test for Adaptive Card replies with TestAdaptor and TestFlow? BotFramework

Have been writing some tests in the enterprise template 4.2.2 of the bot which has is working great for text based responses so far. However when the flow involves Adaptive Cards, is there a way to access the attachments to make sure everything works as intended?
In this dialog, when software is selected, an adaptive card is sent back.
Looks like this from the client side.
https://imgur.com/a/aEDwFYl
[TestMethod]
public async Task TestSoftwareIssue()
{
string resp = "What sort of issue do you have?\n\n" +
" 1. Computer\n" +
" 2. Software\n" +
" 3. Insuffient Permissions for Access\n" +
" 4. Account expired\n" +
" 5. Other";
await GetTestFlow()
.Send(GeneralUtterances.GeneralIssue)
.AssertReply(resp)
.Send("software")
// Check attachment somehow?
.AssertReply("")
.StartTestAsync();
}
Any advice on how the output of adaptive cards can be verified would be great.
I think there needs to be some way to access the activity attachments from the bot sent to the user, having some trouble determining how this could be done right now.
Thanks!
So after some exploring, figured one way to work this out with this function which is part of TestFlow.
/// <param name="validateActivity">A validation method to apply to an activity from the bot.
/// This activity should throw an exception if validation fails.</param>
public TestFlow AssertReply(Action<IActivity> validateActivity, [CallerMemberName] string description = null, uint timeout = 3000)
Then we can create our own verification function which can handle assertions.
public void CheckAttachment(IMessageActivity messageActivity)
{
// Check if content is the same
var messageAttachment = messageActivity.Attachments.First();
// Example attachment
var adaptiveCardJson = File.ReadAllText(#".\Resources\TicketForm.json");
var expected = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
Assert.AreEqual(messageAttachment.Content.ToString(), expected.Content.ToString());
}
The [TestMethod] can then work something like this.
[TestMethod]
public async Task TestSoftwareIssue()
{
await GetTestFlow()
.Send(GeneralUtterances.GeneralIssue)
.AssertReply("Some Response")
.Send("Some Choice")
// .AssertReply("")
.AssertReply(activity => CheckAttachment(activity.AsMessageActivity()))
.StartTestAsync();
}

How to get most recent update in Telegram Bot API

I am struggling on how to get the text of a message to my C#-console tool with a telegram bot. Here is a piece of that is supposed to just print all messages in the telegram channel
private async Task getTelegramMessage()
{
var bot = new Telegram.Bot.TelegramBotClient("token")
var updates = await bot.GetUpdatesAsync();
foreach (var update in updates)
{
Console.WriteLine("Bot: " + update.Message.Text);
}
}
the problem is that i always get all old updates. The maximum length of the array updates is 100. So after I sent 100 messages in the telegram channel, I would only have access to the first 100 messages and no access to the newest. How can I get access to the most recent update? Or can I somehow delete the message after my tool has processed it?
I have seen that the bot provides the Event OnUpdate but I couldnt figure out how to use it.
Thanks a lot for help on that issue.
According documentation, you can use offset -1 to get the last update.
Just put in mind all previous updates will forgotten.
getUpdates Docs
https://api.telegram.org/bot{TOKEN}/getUpdates?offset=-1
oh, I just figured it out. for the offset you have to set the ID returned in the update.
Notes
2. In order to avoid getting duplicate updates, recalculate offset after each server response.
Instead subscribe to the BotOnUpdateReceived event to handle the updates. In main.cs:
Bot.OnUpdate += BotOnUpdateReceived;
Bot.StartReceiving(Array.Empty<UpdateType>());
Console.WriteLine($"Start listening!!");
Console.ReadLine();
Bot.StopReceiving();
And handle the event:
private static async void BotOnUpdateReceived(object sender, UpdateEventArgs e)
{
var message = e.Update.Message;
if (message == null || message.Type != MessageType.Text) return;
var text = message.Text;
Console.WriteLine(text);
await Bot.SendTextMessageAsync(message.Chat.Id, "_Received Update._", ParseMode.Markdown);
}
The Offset is internally working in it and it also internally call GetUpdatesAsync().
From Here you can also get channel post via:
var message = e.Update.ChannelPost.Text; // For Text Messages
I hope it will Help!!

C# autoit WinWaitActive not returning correct value

I'm trying to get the information from a Messagebox that appears after a process runs in the GUI that I'm controlling with AutoIt v3. The messagebox will either show a success message or a fail message and I want to log those outcomes, but it keeps going to the 'failed install' rather than the 'success' and notes it in the log as a failure when I can see the message says success. Any help is appreciated. Here's my code along with my commented thoughts:
internal void Install(string filepath)
{
au3.Send("!i"); //Send ALT+I
au3.WinWaitActive("Select Content Package", "", 20000); //Wait for window
au3.WinActivate("Select Content Package"); //If something else came up focus back on it prior to next line
au3.MouseClick("primary", 337,11); //Click on field as AutoIt cannot access it.
au3.Send(filepath);
au3.Send("{Enter}");
if(au3.WinWaitActive("Program", "successfully installed.", 90) == 1)
{ //WinWaitActive should return 1 if it is successful. The messagebox contains the text "successfully installed."
au3.Send("{Enter}");
writeLog(filepath + " Successfully installed.")
}
else
{ //WinWaitActive should return 0 if timeout, thus triggering this code
au3.Send("{Enter}");
writeLog(filepath + " Failed Install.")
}
}
I resolved my issue. The title in WinWaitActive() is case-sensitive and I missed a capitalization.

Reliably identifying and tracking Asterisk calls using C# and Aster.NET

I have been building a WinForms desktop application using C# that interfaces with Asterisk using Aster.NET (formerly/forked from Asterisk.NET). We're having real trouble reliably identifying and tracking calls that are related to an individual extension/user.
The problem we're having is due to the unpredictable/fuzzy nature of the events fired/triggered by Asterisk, with them being massively variable depending on how the call is routed before it hits an extension.
For example, the event sequence/format is different when: a call hits an IVR before getting blind transferred; if a call hits an IVR before it is attended transferred; if a call goes direct to the user's extension.
This is further hampered by the way that Asterisk tracks each side of the call using a different Unique ID (e.g. the incoming side of the call has a different UID than the received side of the call). Whilst we've managed to account for that in the (subsequently ugly!) code, we're still hitting issues with accounting for the different routing paths the call can take.
As such, I'm looking for any advice on how we can do the following:
Reliably identify an incoming call to a user's extension
We need to be able to identify the extension being called and the originating caller ID (after either a blind or attended transfer and direct call from external)
Reliably track the Unique ID for that incoming call as it's used to link to the call recording
Reliably identify an outgoing call from a user's extension
With the same caveats as above in mind
As it stands at the minute we have an extremely complex chain of event handlers that operate differently dependent on the 'current state' of the app.
To give one example: if we detect a NewStateEvent with a ChannelState of 6 ('Up'), we check if there is an ongoing call in process and that the UIDs match, and if so then the current call has been answered. If the UIDs don't match, but other factors do (e.g. channel, connectedlinenum, etc), then we pick this up as being the 'other side' of the call (i.e. the receiving or incoming side).
I'm not sure if the problem lies with the API or with AMI - but whichever it is it's causing us some real headaches.
Any advice greatly appreciated.
Is it possible for you to update to Asterisk 12? The channel names in AMI are now stable in Asterisk 12.
https://wiki.asterisk.org/wiki/display/AST/AMI+v2+Specification
i'm using package Aster.NET in c# . firstly install latest package of aster.net
than check that code .this code work perfect for me .
manager = new ManagerConnection(address, port, user, password);
manager.UnhandledEvent += new ManagerEventHandler(manager_Events);
manager.NewState += new NewStateEventHandler(Monitoring_NewState);
try
{
// Uncomment next 2 line comments to Disable timeout (debug mode)
// manager.DefaultResponseTimeout = 0;
// manager.DefaultEventTimeout = 0;
manager.Login();
if (manager.IsConnected())
{
Console.WriteLine("user name : " + manager.Username);
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine("Error connect\n" + ex.Message);
manager.Logoff();
Console.ReadLine();
}
void manager_Events(object sender, ManagerEvent e)
{
Console.WriteLine("Event : " + e.GetType().Name);
}
void Monitoring_NewState(object sender, NewStateEvent e)
{
string state = e.State;
string callerID = e.CallerId;
Console.WriteLine("caller num ...", e.CallerIdNum);
//Console.WriteLine("state =", state);
//Console.WriteLine("callerID =", callerID);
if ((state == "Ringing") | (e.ChannelState == "5"))
{
Console.WriteLine("hello rining your phone now ...");
String connectedLineNum;
String connectedLineName;
Dictionary<String, String> attributes = e.Attributes;
attributes.TryGetValue("connectedlinenum", out connectedLineNum);
attributes.TryGetValue("connectedlinename", out connectedLineName);
// "callerID" - called phone number
// "connectedLineNum" - calling phone number
// CallIn. Incoming call
}
else if ((state == "Ring") | (e.ChannelState == "4"))
{
Console.WriteLine("hello out going your call ...");
// CallOut. Outcoming call
}
else if ((state == "Up") | (e.ChannelState == "6"))
{
String connectedLineNum;
String connectedLineName;
Dictionary<String, String> attributes = e.Attributes;
attributes.TryGetValue("connectedlinenum", out connectedLineNum);
attributes.TryGetValue("connectedlinename", out connectedLineName);
// "callerID" - called phone number
// "connectedLineNum" - calling phone number
// human lifted up the phone right no
Console.WriteLine("human lifted up the phone...");
}
}

Fleck WebSockets

I want to use Fleck for my WebSocket project,
Server side looks pretty straightforward, but how to I differentiate opened connections. is there some sort of ID? The only way I can think of is to create GUID in OnOpen event and pass it back to client. is there a smarter solution?
Basic server set up:
socket.OnOpen = () =>
{
Console.WriteLine("Open!");
allSockets.Add(socket);
};
socket.OnClose = () =>
{
Console.WriteLine("Close!");
allSockets.Remove(socket);
};
socket.OnMessage = message =>
{
Console.WriteLine(message);
allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
};
E.G. how would I make a chat room so all connection receive message except for the one sending.
Fleck server here: https://github.com/statianzo/Fleck
Fleck now creates a Guid Id on the WebSocketConnectionInfo for every connected client. This will help in cases where multiple connections are using the same IP. See the related commit here:
https://github.com/statianzo/Fleck/commit/fc037f49362bb41a2bc753a5ff51cc9da40ad824
Ask the user for a user name, and attach the username to the the socket address:
var wsimpl = window.WebSocket || window.mozWebSocket;
window.ws = new wsimpl('http://localhost:8080/myApp_' + userName, myProtocol);
then strip out the userName on the service side after the socket has been opened with socket.WebSocketConnectionInfo.path. There is also a clientip property that can be used also. I am doing this and it works great.
I started something similar to what you are asking I am doing. In my case I am using the ConnectionInfo.Path to differ between what my sockets are doing.
You can gain a lot of information already out of the ConnectionInfo
socket.ConnectionInfo.{Host|Path|Origin|SubProtocol|ClientIPAddress|Cookies}
So to answer your question to give it to everyone but the sender you can differentiate each socket based on the ConnectionInfo (if applicable you could create a UID out of this info also)
As a very basic example:
If you know each Client will have a different IP something like the following would work:
socket.OnMessage = message =>
{
foreach (IWebSocketConnection socketConnection in allSockets.Where(socketConnection => socket.ConnectionInfo.ClientIpAddress != socketConnection.ConnectionInfo.ClientIpAddress))
{
socketConnection.Send("Echo: " + message);
}
};
It's a different socket instance per client, so I would have thought you should be able to do:
allSockets.Where(x => x != socket).ToList().ForEach(s => s.Send("Echo: " + message));

Categories