public async Task HelpAsync() { // Deletes the invoking message if it's not a direct message. if (!Context.IsPrivate) { await Context.Message.DeleteAsync(); } var embed = new EmbedBuilder { Color = new Color(47, 111, 146), Title = "\u2753 Command Help", Description = $"A command can be invoked by prefixing its name with `{Program.COMMAND_PREFIX}`. To see usage " + $"details for a command, use `{Program.COMMAND_PREFIX}help [command]`.\n\nThe following is a " + "list of available commands:" }; // Sorts modules alphabetically and adds a field for each one. foreach (ModuleInfo module in _commands.Modules.OrderBy(m => m.Name)) { _help.AddModuleField(module, ref embed); } // Replies normally if a direct message fails. try { await Context.User.SendMessageAsync(string.Empty, false, embed.Build()); } catch { await ReplyAsync(string.Empty, false, embed.Build()); } await DataBaseUtil.AddCommandAsync("Help", Context); }
public async Task CatFactAsync() { var catFact = "Did you know cats have big bushy tails?"; var name = "Cat Fact 0"; // Gets a fact from the file. if (File.Exists(_dataService.CatFactPath)) { string[] allLines = File.ReadAllLines(_dataService.CatFactPath); int lineNumber = _random.Next(0, allLines.Length); catFact = allLines[lineNumber]; // Splits the name and the fact in the selected line. Match match = Regex.Match(catFact, @"^\w+ Fact \d*", RegexOptions.IgnoreCase); name = match.Value; catFact = catFact.Substring(match.Length).Trim(); } var embed = new EmbedBuilder { ThumbnailUrl = _dataService.GetRandomImgFromUrl("https://content.tophattwaffle.com/BotHATTwaffle/catfacts/"), Color = new Color(230, 235, 240) }; embed.WithAuthor("CAT FACTS!", Context.Message.Author.GetAvatarUrl()); embed.WithFooter("This was cat facts, you cannot unsubscribe."); embed.AddField(name, catFact); await _dataService.ChannelLog($"{Context.Message.Author.Username.ToUpper()} JUST GOT HIT WITH A CAT FACT"); await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("CatFact", Context); }
public async Task TanookiFactAsync() { var tanookiFact = "Did you know Tanooki has a big bushy tail?"; // Gets a fact from the file. if (File.Exists(_dataService.TanookiFactPath)) { string[] allLines = File.ReadAllLines(_dataService.TanookiFactPath); int lineNumber = _random.Next(0, allLines.Length); tanookiFact = allLines[lineNumber]; } var embed = new EmbedBuilder { ThumbnailUrl = _dataService.GetRandomImgFromUrl("https://content.tophattwaffle.com/BotHATTwaffle/tanookifacts/"), Color = new Color(230, 235, 240), Description = tanookiFact }; embed.WithAuthor("TANOOKI FACTS!", Context.Message.Author.GetAvatarUrl()); embed.WithFooter("This was Tanooki facts; you cannot unsubscribe."); await _dataService.ChannelLog($"{Context.Message.Author.Username.ToUpper()} JUST GOT HIT WITH A TANOOKI FACT"); await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("TanookiFact", Context); }
public async Task MuteAsync( [Summary("The user to mute.")] SocketGuildUser user, [Summary("The duration, in minutes, of the mute.")] [RequireBoundaries(1, 43200)] int duration = 5, [Summary("The reason for the mute.")][Remainder] string reason = "No reason provided.") { if (user.Roles.Contains(_data.ModRole)) { await Context.Channel.SendMessageAsync(string.Empty, embed : new EmbedBuilder().WithAuthor("Mods don't mute other Mods...") .WithDescription("Now you 2 need to learn to play nice and get along.")); return; } if (await _mute.MuteAsync(user, (SocketGuildUser)Context.User, duration == 0 ? default(int?) : duration, reason)) { await Context.Channel.SendMessageAsync($"Successfully muted {user}."); } else { await Context.Channel.SendMessageAsync($"{user} is already muted!"); } await DataBaseUtil.AddCommandAsync("Mute", Context); }
public async Task AnnounceAsync( [Summary("A format string or the input for the interactive builder's current prompt.")][Remainder] string input = null) { await Context.Message.DeleteAsync(); if (input != null) { // Builds the embed from a supplied formatting string. var builder = new QuickBuilder(Context); Embed embed = builder.Build(input); if (!string.IsNullOrWhiteSpace(builder.Errors)) { await ReplyAndDeleteAsync($"```{builder.Errors}```", timeout : TimeSpan.FromSeconds(15)); } if (embed == null) { return; // Builder was cancelled. } await SendEmbedAsync(embed, await builder.ParseChannels()); } else { // No formatting string given; interactively builds the embed by prompting the user. var builder = new InteractiveBuilder(Context, Interactive); Embed embed = await builder.BuildAsync(); if (embed == null) { return; // Builder was cancelled or timed out. } await SendEmbedAsync(embed, await builder.PromptDestinationAsync(Context)); } // Helper function the send the embed to all given channels. async Task SendEmbedAsync(Embed embed, IReadOnlyCollection <SocketTextChannel> channels) { if (!channels.Any()) { await ReplyAndDeleteAsync("```No channel mentions were found.```", timeout : TimeSpan.FromSeconds(15)); return; } foreach (SocketTextChannel channel in channels) { await channel.SendMessageAsync(string.Empty, false, embed); } await _data.ChannelLog( $"Embed created by {Context.User} was sent to {string.Join(", ", channels.Select(c => c.Name))}."); await _data.LogChannel.SendMessageAsync(string.Empty, false, embed); } await DataBaseUtil.AddCommandAsync("Announce", Context); }
public async Task StatsAsync( [Summary("The user for which to retrieve statistics. If no user is specified, the invoking user is used.")] SocketUser user = null) { user = user ?? Context.User; CommandUse[] commands = await DataBaseUtil.GetCommandsAsync(user.Id); Shitpost[] shitposts = await DataBaseUtil.GetShitpostsAsync(user.Id); Mute[] mutes = await DataBaseUtil.GetMutesAsync(user.Id); EmbedBuilder embed = new EmbedBuilder().WithAuthor($"Stats for {user}", user.GetAvatarUrl()); if (commands.Any()) { string fav = commands.GroupBy(r => r.command).OrderByDescending(g => g.Count()).Select(g => g.Key).First(); int favCount = commands.Count(c => c.command == fav); embed.AddField("Command Usage", $"Total: `{commands.Length}`\nFavorite: `{fav}` ({favCount})"); } if (shitposts.Any()) { string fav = shitposts.GroupBy(r => r.shitpost).OrderByDescending(g => g.Count()).Select(g => g.Key).First(); int favCount = shitposts.Count(c => c.shitpost == fav); embed.AddField("Shitpost Usage", $"Total: `{shitposts.Length}`\nFavorite: `{fav}` ({favCount})"); } if (mutes.Any()) { Mute mute = mutes.First(); string value = $"Total: {mutes.Length}\nTimestamp: `{mute.Timestamp:yyyy-MM-ddTHH:mm:ssZ}`\nDuration: `"; if (mute.Duration.HasValue) { value += mute.Duration + (mute.Duration == 1 ? "` minute" : "` minutes"); } else { value += "indefinite`"; } if (mute.Reason != null) { value += $"\nReason: `{mute.Reason}`"; } embed.AddField("Latest Mute Information", value); } await ReplyAsync(string.Empty, embed : embed.Build()); await DataBaseUtil.AddCommandAsync("Stats", Context); }
public async Task ActiveAsync([Summary("User to give role to")] SocketGuildUser user) { await _data.ChannelLog($"{user} has been given {_data.ActiveRole.Mention} by {Context.User}"); await ReplyAsync($"{user.Mention} has been given {_data.ActiveRole.Mention}!\n\nThanks for being an active member in our community!"); await((IGuildUser)user).AddRoleAsync(_data.ActiveRole); await DataBaseUtil.AddCommandAsync("Active", Context); }
public async Task SearchAsync( [Summary("The series in which to search.")] string series, [Summary("The term for which to search in the series.")][Remainder] string term) { IUserMessage wait = await ReplyAsync( $":eyes: Searching for **{term}** in **{series}**. This may take a moment! :eyes:"); bool isPrivate = Context.IsPrivate; List <List <string> > results = await _dataService.Search(series, term, isPrivate); // Peforms a search. await _dataService.ChannelLog($"{Context.User} ran a search", $"Series: {series}\nSearch Term: {term}"); // Notifies the user of a lack of search results. if (!results.Any()) { results.Add( new List <string> { "Try a different search term", "http://tophattwaffle.com/faq", "I could not locate anything for the search term you provided. Please try a different search term.", null }); } foreach (List <string> r in results) { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = r[0], IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = r[1], ThumbnailUrl = r[3], Color = new Color(243, 128, 72), Description = r[2] }; await ReplyAsync(string.Empty, false, embed.Build()); } if (!isPrivate) { await wait.DeleteAsync(); } await DataBaseUtil.AddCommandAsync("Search", Context); }
public async Task TanookiLookAsync() { var embed = new EmbedBuilder { ImageUrl = _dataService.GetRandomImgFromUrl("https://content.tophattwaffle.com/BotHATTwaffle/kimjongillookingatthings/"), Color = new Color(138, 43, 226) }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("TanookiIRL", Context); }
public async Task PingAsync() { var builder = new EmbedBuilder { Color = new Color(47, 111, 146), Description = $"*Do you like waffles?*\nIt took me **{_client.Latency} ms** to reach the Discord API." }; await ReplyAsync(string.Empty, false, builder.Build()); await DataBaseUtil.AddCommandAsync("Ping", Context); }
public async Task ShutdownAsync() { await DataBaseUtil.AddCommandAsync("Shutdown", Context); await Context.Message.DeleteAsync(); await _data.ChannelLog($"{Context.Message.Author} is shutting down the bot."); await Context.Client.SetStatusAsync(UserStatus.Invisible); // Workaround for an issue with StopAsync. await Context.Client.StopAsync(); await Task.Delay(2000); // Without the delay, the bot never logs the shutdown. Environment.Exit(0); }
public async Task ClearReservationsAsync( [Summary("The three-letter code which identifies the server to clear.")] string serverCode = null) { if (serverCode == null) { await _playtesting.ClearServerReservations(); } else { await _playtesting.ClearServerReservations(serverCode); } await ReplyAsync(string.Empty, false, _playtesting.DisplayServerReservations()); await DataBaseUtil.AddCommandAsync("ClearReservations", Context); }
public async Task SearchAsync( [Summary("The term for which to search.")][Remainder] string term) { await Context.Channel.TriggerTypingAsync(); term = term.Replace(' ', '+'); string builtUrl = $"https://developer.valvesoftware.com/w/index.php?search={term}&title=Special%3ASearch&go=Go"; string siteTitle; // Download web page title and store to string. using (var client = new WebClient()) { siteTitle = client.DownloadString(builtUrl); } var regex = new Regex(@"(?<=<title.*>)([\s\S]*)(?=</title>)", RegexOptions.IgnoreCase); siteTitle = regex.Match(siteTitle).Value.Trim(); // Defaults the URL if it isn't properly formatted. if (!Uri.IsWellFormedUriString(builtUrl, UriKind.Absolute)) { builtUrl = "https://developer.valvesoftware.com/wiki/Main_Page"; term = "Valve Developer Community"; } var builder = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = $"This is what I was able to find for {term}", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Search Results", Url = builtUrl, ImageUrl = "https://developer.valvesoftware.com/w/skins/valve/images-valve/logo.png", Color = new Color(71, 126, 159), Description = siteTitle }; await ReplyAsync(string.Empty, false, builder.Build()); await DataBaseUtil.AddCommandAsync("VDC", Context); }
public async Task AboutAsync() { DateTime buildDate = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime.ToUniversalTime(); var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "About BotHATTwaffle", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Url = "https://www.tophattwaffle.com/", ThumbnailUrl = _client.CurrentUser.GetAvatarUrl(), Color = new Color(130, 171, 206), Description = "BotHATTwaffle was started to centralize Source Engine Discord server functions that were " + "fractured between multiple bots. This bot was my first attempt at a real C# program that other " + "people would interact with.\n\nPlease let me know if you have any suggests or find bugs!" }; embed.AddInlineField("Author", "[TopHATTwaffle](https://github.com/tophattwaffle)"); embed.AddInlineField( "Contributors", "[BenBlodgi](https://github.com/BenVlodgi)\n" + "[Mark](https://github.com/MarkKoz)\n" + "[JimWood](https://github.com/JamesT-W)"); embed.AddInlineField( "Build Date", $"{buildDate:yyyy-MM-ddTHH:mm:ssK}\n[Changelog](https://github.com/tophattwaffle/BotHATTwaffle/commits/master)"); embed.AddInlineField( "Libraries", "[Discord.net V1.0.2](https://github.com/RogueException/Discord.Net)\n" + "[CoreRCON](https://github.com/ScottKaye/CoreRCON)\n" + "[Html Agility Pack](http://html-agility-pack.net/)\n" + "[Newtonsoft Json.NET](https://www.newtonsoft.com/json)\n" + "[SSH.NET](https://github.com/sshnet/SSH.NET/)\n" + "[FluentFTP](https://github.com/robinrodricks/FluentFTP)\n" + "[EF Core](https://docs.microsoft.com/en-us/ef/core/)"); embed.WithFooter("Build date"); embed.WithTimestamp(buildDate); await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("About", Context); }
public async Task SuppressAsync(int input = 0) { if (input == 0) { await ReplyAsync($"```True means this alert will not be fired until the announcement " + $"message has changed.\n\nCurrent Alert Flags:\n{_playtesting.GetAnnounceFlags()}```"); return; } _playtesting.SuppressAnnounce(input); await ReplyAsync($"```True means this alert will not be fired until the announcement " + $"message has changed.\n\nCurrent Alert Flags:\n{_playtesting.GetAnnounceFlags()}```"); await _data.ChannelLog($"{Context.User} changed playtest alert flag suppression", _playtesting.GetAnnounceFlags()); await DataBaseUtil.AddCommandAsync("Suppress", Context); }
public async Task ShadersAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Shader Resources", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Fields = { new EmbedFieldBuilder { Name = "General", Value = "[Shader](https://developer.valvesoftware.com/wiki/Shader)\n" + "[Shader Authoring](https://developer.valvesoftware.com/wiki/Shader_Authoring)\n" + "[Guide to Shaders](http://www.bit-tech.net/reviews/tech/guide_to_shaders/1/)\n" + "[Introduction to Shaders](http://www.moddb.com/games/half-life-2/tutorials/introduction-to-shaders)\n" + "[Post Process Shaders](http://www.moddb.com/games/half-life-2/tutorials/post-process-shader)", IsInline = false }, new EmbedFieldBuilder { Name = "Language", Value = "[High-Level Shader Language](https://en.wikipedia.org/wiki/High-Level_Shading_Language)", IsInline = false }, new EmbedFieldBuilder { Name = "Types", Value = "[Vertex](https://developer.valvesoftware.com/wiki/Shader#Vertex_shaders)\n" + "[Pixel](https://developer.valvesoftware.com/wiki/Shader#Pixel_shaders)", IsInline = false } }, Color = new Color(240, 235, 230), Description = "Here are lists of popular shader resources:" }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("Shaders", Context); }
public async Task DumpSettingsAsync() { await Context.Message.DeleteAsync(); string reply = string.Join("\n", _data.Config.Select(kvp => $"{kvp.Key}: {kvp.Value}")); reply = reply.Replace(_data.Config["botToken"], "[REDACTED]"); try { await Context.Message.Author.SendMessageAsync($"```{reply}```"); } catch { // Do nothing if the user doesn't accept DMs. } await _data.ChannelLog($"{Context.User} dumped the settings."); await DataBaseUtil.AddCommandAsync("DumpSettings", Context); }
public async Task WallWormAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Check out Wall Worm", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "https://dev.wallworm.com/", ThumbnailUrl = "https://content.tophattwaffle.com/BotHATTwaffle/worm_logo.png", Color = new Color(21, 21, 21), Description = "Wall Worm tools enable developers to design assets and level in Autodesk's 3ds Max and export " + "them into the Source Engine. It's the best thing to ever happen to Source Engine modelling." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("WallWorm", Context); }
public async Task PlaytesterAsync() { var user = Context.User as SocketGuildUser; if (user.Roles.Contains(_dataService.PlayTesterRole)) { await _dataService.ChannelLog($"{Context.User} has unsubscribed from playtest notifications!"); await ReplyAsync($"Sorry to see you go from playtest notifications {Context.User.Mention}!"); await((IGuildUser)user).RemoveRoleAsync(_dataService.PlayTesterRole); } else { await _dataService.ChannelLog($"{Context.User} has subscribed to playtest notifications!"); await ReplyAsync($"Thanks for subscribing to playtest notifications {Context.User.Mention}!"); await((IGuildUser)user).AddRoleAsync(_dataService.PlayTesterRole); } await DataBaseUtil.AddCommandAsync("Playtester", Context); }
public async Task BspSourceAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Download BSPSource", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "https://www.tophattwaffle.com/downloads/bspsource/", ThumbnailUrl = "https://content.tophattwaffle.com/BotHATTwaffle/BSPSource_icon.png", Color = new Color(84, 137, 71), Description = "BSPSource is a tool for decompiling Source's BSP (Binary Space Partition) files into VMF " + "(Valve Map Format) files that can be opened with Hammer. It is a great tool to see how things " + "are done in a map. It should not be used to steal content." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("BSPSource", Context); }
public async Task LogCheckerAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Interlopers Compile Log Checker", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "http://www.interlopers.net/errors", ThumbnailUrl = "https://www.tophattwaffle.com/wp-content/uploads/2017/12/selectall.jpg", Color = new Color(84, 137, 71), Description = "The compile log checker on Interlopers is a web tool which analyses compile logs of maps to " + "detect compilation issues and propose solutions. Simply copy and paste an entire log or a " + "section with an error and click the button to have the log checked." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("Log", Context); }
public async Task VmtEditorAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Download VMT Editor", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "https://gira-x.github.io/VMT-Editor/", ThumbnailUrl = "https://content.tophattwaffle.com/BotHATTwaffle/vmteditor.png", Color = new Color(50, 50, 50), Description = "VMT Editor is, hands down, one of the best VMT (Valve Material Type) creation tools that " + "exists for the Source engine. It quickly became a standard tool for most designers that " + "regularly create VMT files. Created by Yanzl over at MapCore." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("VMTEditor", Context); }
public async Task VtfEditAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Download VTFEdit", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "https://www.tophattwaffle.com/downloads/vtfedit/", ThumbnailUrl = "https://content.tophattwaffle.com/BotHATTwaffle/vtfedit.png", Color = new Color(255, 206, 199), Description = "VTFEdit is a lightweight tool used to convert images into Valve's proprietary format - VTF " + "(Valve Texture Format). Because it has a GUI, it is substantially easier to use than Valve's " + "own CLI tool, VTEX (Valve Texture Tool)." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("VTFEdit", Context); }
public async Task VideAsync() { var embed = new EmbedBuilder { Author = new EmbedAuthorBuilder { Name = "Download VIDE", IconUrl = _client.Guilds.FirstOrDefault()?.IconUrl }, Title = "Click Here", Url = "https://www.tophattwaffle.com/downloads/vide/", ThumbnailUrl = "https://content.tophattwaffle.com/BotHATTwaffle/vide.png", Color = new Color(50, 50, 50), Description = "VIDE (Valve Integrated Development Environment) is a 3rd-party program which contains various " + "tools. It is popular for its pakfile lump editor (packing assets into a level), but it can do " + "so much more than that." }; await ReplyAsync(string.Empty, false, embed.Build()); await DataBaseUtil.AddCommandAsync("VIDE", Context); }
public async Task UnmuteAsync( [Summary("The user to unmute.")] SocketGuildUser user = null, [Summary("The reason for the unmute.")][Remainder] string reason = "A moderator has taken mercy on you by lifting the mute.") { if (user != null) { if (await _mute.UnmuteAsync(user, (SocketGuildUser)Context.User, reason)) { await ReplyAsync($"Unmuted {user}."); } else { await ReplyAsync($"Failed to unmute {user} because the user isn't muted."); } } else { string reply = null; foreach (Mute mute in await DataBaseUtil.GetActiveMutesAsync()) { //TODO: Move this to >MuteHistory. It is only here because I'm too lazy and this was easier... reply += $"Name: {mute.Username}\nMuted at: {mute.Timestamp:yyyy-MM-ddTHH:mm:ssZ}\n" + $"Duration: {mute.Duration?.ToString() ?? "indefinite"}\nReason: {mute.Reason ?? "None"}\n" + $"Expires at: {mute.Timestamp.AddMinutes(mute.Duration ?? 0)}"; } if (reply == null) { reply = "No mutes found!"; } await ReplyAsync($"Current Mutes: {reply}"); } await DataBaseUtil.AddCommandAsync("Unmute", Context); }
public async Task ReloadAsync() { try { await _data.DeserialiseConfig(true); _timer.Stop(); _timer.Start(); await ReplyAsync("```Successfully reloaded settings.```"); await _data.ChannelLog($"{Context.User} successfully reloaded the settings."); } catch (InvalidOperationException e) { await _data.ChannelLog($"{Context.User} failed to reload the settings.", e.Message); await Context.Channel.SendMessageAsync( $"An error occurred reloading the config. Reverting to the previous config. ```{e.Message}```"); } await DataBaseUtil.AddCommandAsync("Reload", Context); }
public async Task ReleasePublicTestCommandAsync([Remainder] string command = null) { Server server = null; if (!_playtesting.CanReserve) { await ReplyAsync($"```Servers cannot be reserved at this time." + $"\nServer reservation is blocked 1 hour before a scheduled test, and resumes once the calendar event has passed.```"); return; } bool hasServer = false; foreach (UserData u in _playtesting.UserData) { if (u.User != Context.Message.Author) { continue; } server = u.ReservedServer; hasServer = true; } if (hasServer) { await ReplyAsync("```Releasing Server reservation.```"); await _playtesting.ClearServerReservations(server.name); } else { await ReplyAsync("```I could not locate a server reservation for your account.```"); } await DataBaseUtil.AddCommandAsync("ReleaseServer", Context); }
public async Task MuteHistoryAsync( [Summary("The user for which to retrieve mute history.")] SocketGuildUser user, [RequireBoundaries(1, 25)] int quantity = 10) { Mute[] mutes = await DataBaseUtil.GetMutesAsync(user.Id, quantity); int total = mutes.Length; var pages = new List <EmbedBuilder>(); await DataBaseUtil.AddCommandAsync("MuteHistory", Context); if (mutes.Any()) { await BuildPage(); } else { var embed = new EmbedBuilder { ThumbnailUrl = user.GetAvatarUrl(), Color = new Color(243, 128, 72) }; embed.WithAuthor($"No mutes for {user}!"); embed.Description = "Who knew we have users that could behave!"; await ReplyAsync(string.Empty, embed : embed.Build()); return; } async Task BuildPage(EmbedFieldBuilder firstField = null) { var embed = new EmbedBuilder { ThumbnailUrl = user.GetAvatarUrl(), Color = new Color(243, 128, 72) }; embed.WithAuthor($"{user}'s Most Recent Mutes"); if (firstField != null) { embed.AddField(firstField); } foreach (Mute mute in mutes) { string timestamp = mute.Timestamp.ToString("yyyy-MM-ddTHH:mm:ssZ"); string value = $"Muted by: `{mute.MuterName}`"; string valueEnd; if (mute.Duration.HasValue) { string units = mute.Duration > 1 ? "minutes" : "minute"; DateTimeOffset unmuted = mute.Timestamp.AddMinutes(mute.Duration.Value); valueEnd = $"\nDuration: `{mute.Duration}` {units}\nUnmuted at: `{unmuted:yyyy-MM-ddTHH:mm:ssZ}`"; } else { valueEnd = "\nDuration: `indefinite`"; } string reason = null; if (mute.Reason != null) { value += "\nReason: `"; valueEnd = "`" + valueEnd; reason = mute.Reason.Truncate(1024 - value.Length - valueEnd.Length, true); } embed.AddField(timestamp, value + reason + valueEnd); if (embed.Length() > 6000 - 26) // Total char limit - maximum possible footer length. { EmbedFieldBuilder field = embed.Fields.Pop(); // Re-use the field in the next embed. pages.Add(embed); mutes = mutes.Skip(embed.Fields.Count + 1).ToArray(); // Skips already processed records. await BuildPage(field); // Process the remaining records. return; } } pages.Add(embed); } // Sets the footer text and sends each embed. if (pages.Count > 1) { for (var i = 0; i < pages.Count;) { EmbedBuilder embed = pages[i]; embed.WithFooter($"{total} Results | Page {++i} of {pages.Count}"); await ReplyAsync(string.Empty, embed : embed.Build()); } } else { await ReplyAsync(string.Empty, embed : pages.Single().Build()); } }
public async Task HelpAsync([Summary("The command for which to get help.")] string command) { // Deletes the invoking message if it's not a direct message. if (!Context.IsPrivate) { await Context.Message.DeleteAsync(); } SearchResult result = _commands.Search(Context, command); if (!result.IsSuccess) { await ReplyAsync($"No commands matching **{command}** were found."); return; } // Iterates command search results. for (var i = 0; i < result.Commands.Count; ++i) { CommandInfo cmd = result.Commands[i].Command; string parameters = _help.GetParameters(cmd.Parameters); string contexts = _help.GetContexts(cmd.Preconditions); string permissions = _help.GetPermissions(cmd.Preconditions); string roles = _help.GetRoles(cmd.Preconditions, Context); // Creates the embed. var embed = new EmbedBuilder { Color = new Color(47, 111, 146), Title = $"\u2753 `{cmd.Name}` Help", Description = $"`{_help.GetUsage(cmd)}`\n{cmd.Summary}" }; // Only includes result count if there's more than one. // Only includes message about optional parameters if the command has any. embed.WithFooter( (result.Commands.Count > 1 ? $"Result {i + 1}/{result.Commands.Count}." : string.Empty) + (cmd.Parameters.Any(p => p.IsOptional) ? " Angle brackets and italics denote optional arguments/parameters." : string.Empty)); if (!string.IsNullOrWhiteSpace(cmd.Remarks)) { embed.AddField("Details", cmd.Remarks); } if (!string.IsNullOrWhiteSpace(parameters)) { embed.AddField("Parameters", parameters); } if (!string.IsNullOrWhiteSpace(contexts)) { embed.AddInlineField("Contexts", contexts); } if (!string.IsNullOrWhiteSpace(permissions)) { embed.AddInlineField("Permissions", permissions); } if (!string.IsNullOrWhiteSpace(roles)) { embed.AddInlineField("Roles", roles); } // Excludes the command's name from the aliases. if (cmd.Aliases.Count > 1) { embed.AddInlineField( "Aliases", string.Join("\n", cmd.Aliases.Where(a => !a.Equals(cmd.Name, StringComparison.OrdinalIgnoreCase)))); } // Replies normally if a direct message fails. try { await Context.User.SendMessageAsync(string.Empty, false, embed.Build()); } catch { await ReplyAsync(string.Empty, false, embed.Build()); } } await DataBaseUtil.AddCommandAsync("Help", Context); }
public async Task EditServers(string action = null, [Remainder] string values = null) { if (!_playtesting.CanReserve) { //Can't reserve, meaning we are close to a test. Don't want to edit fields. await ReplyAsync("You cannot edit servers this close to a playtest. Try again later."); return; } if (action.StartsWith("a", StringComparison.OrdinalIgnoreCase)) { string[] vars = values.Split('|'); if (vars.Length != 8) { await ReplyAsync("You didn't provide all 8 parameters. Please provide all 8 and try again." + "\nYour message was deleted as it may have contained a password."); await Context.Message.DeleteAsync(); return; } if (vars[0].Length != 3) { //Enforce length during the add because SQLite does not support min/max lengths on TEXT fields. await ReplyAsync("Server name must be 3 characters long. Please provide 3 characters as the name and try again." + "\nYour message was deleted as it may have contained a password."); await Context.Message.DeleteAsync(); return; } //Validate FTP type before entry switch (vars[7]) { case "ftp": break; case "sftp": break; case "ftps": break; default: await ReplyAsync("Invalid FTP type. Please provide `ftp`, `ftps`, or `sftp` and try again." + "\nYour message was deleted as it may have contained a password."); await Context.Message.DeleteAsync(); return; } await DataBaseUtil.AddServerAsync(new Server() { name = vars[0], description = vars[1], address = vars[2], rcon_password = vars[3], ftp_path = vars[4], ftp_username = vars[5], ftp_password = vars[6], ftp_type = vars[7] }); await ReplyAsync("Server added! Your message was removed as it contained passwords."); await Context.Message.DeleteAsync(); } else if (action.StartsWith("g", StringComparison.OrdinalIgnoreCase)) { var server = await DataBaseUtil.GetServerAsync(values.Substring(0, 3)); if (server != null) { await ReplyAsync($"`{server.ToString()}`"); } else { await ReplyAsync($"I could not find a server with that name."); } } else if (action.StartsWith("r", StringComparison.OrdinalIgnoreCase)) { Server removedServer = await DataBaseUtil.GetServerAsync(values.Substring(0, 3)); if (removedServer != null) { await ReplyAsync($"Removing server\n`{removedServer.ToString()}`"); await DataBaseUtil.RemoveServerAsync(removedServer); } else { await ReplyAsync($"I could not find a server with that name."); return; } } else { await ReplyAsync("Invalid command. Please see the help text."); } await DataBaseUtil.AddCommandAsync("EditServers", Context); }