diff --git a/EmperorPalpatine/ChatlogQuery.cs b/EmperorPalpatine/ChatlogQuery.cs index 0d9934e..6420360 100644 --- a/EmperorPalpatine/ChatlogQuery.cs +++ b/EmperorPalpatine/ChatlogQuery.cs @@ -7,5 +7,6 @@ public class ChatlogQuery public DateTime? FromTimestamp { get; set; } public DateTime? ToTimestamp { get; set; } public int? Count { get; set; } + public bool Random { get; set; } public string? Regex { get; set; } } \ No newline at end of file diff --git a/EmperorPalpatine/Database.cs b/EmperorPalpatine/Database.cs index 4862140..5153dd1 100644 --- a/EmperorPalpatine/Database.cs +++ b/EmperorPalpatine/Database.cs @@ -6,22 +6,21 @@ namespace EmperorPalpatine; public class Database { - private MySqlConnection db; - + private readonly string connstr; public Database(ConfigDatabase config) { - var connstr = new MySqlConnectionStringBuilder + connstr = new MySqlConnectionStringBuilder { Server = config.Host, UserID = config.Username, Password = config.Password, Database = config.Database, - }; - db = new MySqlConnection(connstr.ToString()); + }.ToString(); } public async Task InitAsync() { + await using var db = new MySqlConnection(connstr); await db.OpenAsync(); using var cmd = db.CreateCommand(); cmd.CommandText = """ @@ -46,6 +45,8 @@ public class Database public async Task LogChatMessageAsync(string vm, string username, string message) { + await using var db = new MySqlConnection(connstr); + await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "INSERT INTO chatlogs (vm, username, message) VALUES (@vm, @username, @message)"; cmd.Parameters.AddWithValue("@vm", vm); @@ -56,6 +57,8 @@ public class Database public async Task LogIPAsync(string vm, string username, IPAddress ip) { + await using var db = new MySqlConnection(connstr); + await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT COUNT(ip) FROM iplog WHERE ip = @ip AND date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) AND vm = @vm AND username = @username"; cmd.Parameters.AddWithValue("@ip", ip.GetAddressBytes()); @@ -70,6 +73,8 @@ public class Database public async Task GetChatlogsAsync(ChatlogQuery q) { + await using var db = new MySqlConnection(connstr); + await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM chatlogs"; List where = new(); @@ -104,7 +109,7 @@ public class Database } if (q.Count != null) { - cmd.CommandText += " ORDER BY date DESC LIMIT @count"; + cmd.CommandText += $" ORDER BY {(q.Random ? "RAND()" : "date DESC")} LIMIT @count"; cmd.Parameters.AddWithValue("@count", q.Count); } await using var reader = await cmd.ExecuteReaderAsync(); @@ -126,6 +131,8 @@ public class Database public async Task GetIPFromUsernameAsync(string username) { + await using var db = new MySqlConnection(connstr); + await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM iplog WHERE username = @username"; cmd.Parameters.AddWithValue("@username", username); @@ -146,6 +153,8 @@ public class Database public async Task GetUsernameFromIPAsync(IPAddress ip) { + await using var db = new MySqlConnection(connstr); + await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM iplog WHERE ip = @ip"; cmd.Parameters.AddWithValue("@ip", ip.GetAddressBytes()); diff --git a/EmperorPalpatine/DiscordCommands.cs b/EmperorPalpatine/DiscordCommands.cs index 2a7077f..04d6f88 100644 --- a/EmperorPalpatine/DiscordCommands.cs +++ b/EmperorPalpatine/DiscordCommands.cs @@ -9,7 +9,7 @@ namespace EmperorPalpatine; public class DiscordCommands : ApplicationCommandModule { [SlashCommand("vm", "Get info from a VM")] - public async Task VM(InteractionContext ctx, [ChoiceProvider(typeof(VMAutocompleteProvider))] [Option("vm", "VM to get info from")] string VM) { + public async Task VM(InteractionContext ctx, [Autocomplete(typeof(VMAutocompleteProvider))] [Option("vm", "VM to get info from")] string VM) { if (Program.VMs.All(v => v.Config.Name != VM)) { await ctx.CreateResponseAsync("No VM by that name found."); return; @@ -71,7 +71,7 @@ public class DiscordCommands : ApplicationCommandModule [SlashCommand("ban", "Ban a user")] public async Task Ban(InteractionContext ctx, [Option("username", "User to ban")] string username, - [Option("vm", "VM to ban from")] [ChoiceProvider(typeof(VMAutocompleteProvider))] string VM) { + [Option("vm", "VM to ban from")] [Autocomplete(typeof(VMAutocompleteProvider))] string VM) { if (Program.VMs.All(v => v.Config.Name != VM)) { await ctx.CreateResponseAsync("No VM by that name found."); return; @@ -94,7 +94,7 @@ public class DiscordCommands : ApplicationCommandModule [SlashCommand("kick", "Kick a user")] public async Task Kick(InteractionContext ctx, [Option("username", "User to kick")] string username, - [Option("vm", "VM to kick from"), ChoiceProvider(typeof(VMAutocompleteProvider))] string VM) { + [Option("vm", "VM to kick from"), Autocomplete(typeof(VMAutocompleteProvider))] string VM) { if (Program.VMs.All(v => v.Config.Name != VM)) { await ctx.CreateResponseAsync("No VM by that name found."); return; @@ -117,7 +117,7 @@ public class DiscordCommands : ApplicationCommandModule [SlashCommand("reboot", "Reboot a VM")] public async Task Reboot(InteractionContext ctx, - [Option("vm", "VM to reboot"), ChoiceProvider(typeof(VMAutocompleteProvider))] string VM) + [Option("vm", "VM to reboot"), Autocomplete(typeof(VMAutocompleteProvider))] string VM) { if (Program.VMs.All(v => v.Config.Name != VM)) { await ctx.CreateResponseAsync("No VM by that name found."); @@ -137,7 +137,7 @@ public class DiscordCommands : ApplicationCommandModule [SlashCommand("restore", "Restore a VM")] public async Task Restore(InteractionContext ctx, - [Option("vm", "VM to restore"), ChoiceProvider(typeof(VMAutocompleteProvider))] string VM) + [Option("vm", "VM to restore"), Autocomplete(typeof(VMAutocompleteProvider))] string VM) { if (Program.VMs.All(v => v.Config.Name != VM)) { await ctx.CreateResponseAsync("No VM by that name found."); @@ -196,14 +196,35 @@ public class DiscordCommands : ApplicationCommandModule } await ctx.EditResponseAsync(new DiscordWebhookBuilder().AddEmbeds(IPEmbeds)); } + + [SlashCommand("quote", "Quote a user")] + public async Task Quote(InteractionContext ctx, [Option("username", "User to quote")] string username) + { + await ctx.DeferAsync(); + var chat = await Program.Database.GetChatlogsAsync(new ChatlogQuery + { + Username = username, + Count = 1, + Random = true + }); + if (chat.Length == 0) + { + await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"@No messages found for {username}")); + return; + } + await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent($"> {chat[0].Message}\n- {chat[0].Username}")); + } } -public class VMAutocompleteProvider : IChoiceProvider { - public async Task> Provider() { - var list = new List(); +public class VMAutocompleteProvider : IAutocompleteProvider { + + public Task> Provider(AutocompleteContext ctx) + { + var list = new List(); foreach (ConfigVM vm in Program.Config.VMs) { - list.Add(new DiscordApplicationCommandOptionChoice(vm.Name, vm.Name)); + list.Add(new DiscordAutoCompleteChoice(vm.Name, vm.Name)); } - return list.ToArray(); + if (list.Count > 25) list.RemoveRange(24, list.Count - 25); + return Task.FromResult(list.AsEnumerable()); } } \ No newline at end of file diff --git a/EmperorPalpatine/VM.cs b/EmperorPalpatine/VM.cs index a716153..93dd698 100644 --- a/EmperorPalpatine/VM.cs +++ b/EmperorPalpatine/VM.cs @@ -32,6 +32,28 @@ public class VM this.cvm.ConnectionClosed += CvmOnConnectionClosed; this.cvm.UserRenamed += (_, e) => CheckUsername(e.User); this.cvm.UserJoined += (_, e) => CheckUsername(e); + this.cvm.RegisterCommand("+quote", QuoteCommand); + } + + private async void QuoteCommand(string username, string[] args) + { + if (args.Length != 1) + { + await cvm.SendChat($"@{username} Usage: +quote "); + return; + } + var chat = await database.GetChatlogsAsync(new ChatlogQuery + { + Username = args[0], + Count = 1, + Random = true + }); + if (chat.Length == 0) + { + await cvm.SendChat($"@{username} No messages found for {args[0]}"); + return; + } + await cvm.SendXSSChat($"\"{chat[0].Message}\" - {chat[0].Username}"); } private void CvmOnConnectionClosed(object? sender, EventArgs e)