From 94df384934a3b8f82d1b3f98e51b4a8ca1268b10 Mon Sep 17 00:00:00 2001 From: EmotionChild Date: Sun, 21 Aug 2022 19:34:11 +1200 Subject: [PATCH] Updated commands --- SupportChild/Commands/AddCategoryCommand.cs | 71 ++++ SupportChild/Commands/AddCommand.cs | 145 +++----- SupportChild/Commands/AddMessageCommand.cs | 117 +++--- SupportChild/Commands/AddStaffCommand.cs | 127 +++---- SupportChild/Commands/AdminCommands.cs | 200 ++++++++++ SupportChild/Commands/AssignCommand.cs | 189 ++++------ SupportChild/Commands/BlacklistCommand.cs | 115 ++---- SupportChild/Commands/CloseCommand.cs | 212 ++++++----- .../Commands/CreateButtonPanelCommand.cs | 81 +++++ .../CreateSelectionBoxPanelCommand.cs | 79 ++++ SupportChild/Commands/ListAssignedCommand.cs | 117 +++--- SupportChild/Commands/ListCommand.cs | 162 ++++----- SupportChild/Commands/ListOldestCommand.cs | 71 ---- SupportChild/Commands/ListOpen.cs | 60 +++ .../Commands/ListUnassignedCommand.cs | 98 ++--- SupportChild/Commands/MoveCommand.cs | 159 ++++---- SupportChild/Commands/NewCommand.cs | 342 ++++++++++++------ SupportChild/Commands/RandomAssignCommand.cs | 289 +++++++-------- SupportChild/Commands/ReloadCommand.cs | 38 -- .../Commands/RemoveCategoryCommand.cs | 41 +++ SupportChild/Commands/RemoveMessageCommand.cs | 97 ++--- SupportChild/Commands/RemoveStaffCommand.cs | 127 ++----- SupportChild/Commands/SayCommand.cs | 111 +++--- SupportChild/Commands/SetSummaryCommand.cs | 89 ++--- SupportChild/Commands/SetTicketCommand.cs | 98 ----- SupportChild/Commands/StatusCommand.cs | 55 +-- SupportChild/Commands/SummaryCommand.cs | 76 ++-- SupportChild/Commands/ToggleActiveCommand.cs | 102 ++---- SupportChild/Commands/TranscriptCommand.cs | 241 +++++------- SupportChild/Commands/UnassignComand.cs | 91 ++--- SupportChild/Commands/UnblacklistCommand.cs | 115 ++---- SupportChild/Commands/UnsetTicketCommand.cs | 70 ---- 32 files changed, 1926 insertions(+), 2059 deletions(-) create mode 100644 SupportChild/Commands/AddCategoryCommand.cs create mode 100644 SupportChild/Commands/AdminCommands.cs create mode 100644 SupportChild/Commands/CreateButtonPanelCommand.cs create mode 100644 SupportChild/Commands/CreateSelectionBoxPanelCommand.cs delete mode 100644 SupportChild/Commands/ListOldestCommand.cs create mode 100644 SupportChild/Commands/ListOpen.cs delete mode 100644 SupportChild/Commands/ReloadCommand.cs create mode 100644 SupportChild/Commands/RemoveCategoryCommand.cs delete mode 100644 SupportChild/Commands/SetTicketCommand.cs delete mode 100644 SupportChild/Commands/UnsetTicketCommand.cs diff --git a/SupportChild/Commands/AddCategoryCommand.cs b/SupportChild/Commands/AddCategoryCommand.cs new file mode 100644 index 0000000..3656fdb --- /dev/null +++ b/SupportChild/Commands/AddCategoryCommand.cs @@ -0,0 +1,71 @@ +using System.Threading.Tasks; +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +public class AddCategoryCommand : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("addcategory", "Adds a category to the ticket bot letting users open tickets in them.")] + public async Task OnExecute(InteractionContext command, [Option("Title", "The name to display on buttons and in selection boxes.")] string title, [Option("Category", "The category to add.")] DiscordChannel category) + { + if (!category.IsCategory) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "That channel is not a category." + }, true); + return; + } + + if (string.IsNullOrWhiteSpace(title)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Invalid category title specified." + }, true); + return; + } + + if (Database.TryGetCategory(category.Id, out Database.Category _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "That category is already registered." + }, true); + return; + } + + if (Database.TryGetCategory(title, out Database.Category _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is already a category with that title." + }, true); + return; + } + + if (Database.AddCategory(title, category.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Category added." + }, true); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed adding the category to the database." + }, true); + } + } +} \ No newline at end of file diff --git a/SupportChild/Commands/AddCommand.cs b/SupportChild/Commands/AddCommand.cs index 64e5935..47b92f8 100644 --- a/SupportChild/Commands/AddCommand.cs +++ b/SupportChild/Commands/AddCommand.cs @@ -1,107 +1,82 @@ using System; using System.Threading.Tasks; using DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class AddCommand : ApplicationCommandModule { - public class AddCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("add", "Adds a user to a ticket")] + public async Task OnExecute(InteractionContext command, [Option("User", "User to add to ticket.")] DiscordUser user) { - [Command("add")] - [Description("Adds a user to a ticket.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + // Check if ticket exists in the database + if (!Database.IsOpenTicket(command.Channel.Id)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "add")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; + } + + DiscordMember member; + try + { + member = (user == null ? command.Member : await command.Guild.GetMemberAsync(user.Id)); + + if (member == null) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the add command but did not have permission."); + Description = "Could not find that user in this server." + }, true); return; } - - // Check if ticket exists in the database - if (!Database.IsOpenTicket(command.Channel.Id)) + } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } + Color = DiscordColor.Red, + Description = "Could not find that user in this server." + }, true); + return; + } - string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString); - foreach (string parsedArg in parsedArgs) + try + { + await command.Channel.AddOverwriteAsync(member, Permissions.AccessChannels); + await command.CreateResponseAsync(new DiscordEmbedBuilder { - if (!ulong.TryParse(parsedArg, out ulong userID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - continue; - } + Color = DiscordColor.Green, + Description = "Added " + member.Mention + " to ticket." + }); - DiscordMember mentionedMember; - try + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { - mentionedMember = await command.Guild.GetMemberAsync(userID); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not find user on this server)" - }; - await command.RespondAsync(error); - continue; - } - - try - { - await command.Channel.AddOverwriteAsync(mentionedMember, Permissions.AccessChannels, Permissions.None); - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Added " + mentionedMember.Mention + " to ticket." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = mentionedMember.Mention + " was added to " + command.Channel.Mention + - " by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - catch (Exception) - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Could not add <@" + parsedArg + "> to ticket, unknown error occured." - }; - await command.RespondAsync(message); - } + Color = DiscordColor.Green, + Description = member.Mention + " was added to " + command.Channel.Mention + + " by " + command.Member.Mention + "." + }); } } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Could not add " + member.Mention + " to ticket, unknown error occured." + }, true); + } } } \ No newline at end of file diff --git a/SupportChild/Commands/AddMessageCommand.cs b/SupportChild/Commands/AddMessageCommand.cs index a2e6606..6ffa491 100644 --- a/SupportChild/Commands/AddMessageCommand.cs +++ b/SupportChild/Commands/AddMessageCommand.cs @@ -1,76 +1,53 @@ -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using DSharpPlus.Entities; using System.Threading.Tasks; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class AddMessageCommand : ApplicationCommandModule { - public class AddMessageCommand : BaseCommandModule - { - [Command("addmessage")] - [Description("Adds a new message for the 'say' command.")] - public async Task OnExecute(CommandContext command, string identifier, [RemainingText] string message) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "addmessage")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the addmessage command but did not have permission."); - return; - } + [SlashRequireGuild] + [SlashCommand("addmessage", "Adds a new message for the 'say' command.")] + public async Task OnExecute(InteractionContext command, + [Option("Identifier", "The identifier word used in the /say command.")] string identifier, + [Option("Message", "The message the /say command will return.")] string message) + { + if (string.IsNullOrEmpty(message)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "No message specified." + }, true); + return; + } - if (string.IsNullOrEmpty(message)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "No message specified." - }; - await command.RespondAsync(error); - return; - } - - if (Database.TryGetMessage(identifier.ToLower(), out Database.Message _)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "There is already a message with that identifier." - }; - await command.RespondAsync(error); - return; - } + if (Database.TryGetMessage(identifier.ToLower(), out Database.Message _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is already a message with that identifier." + }, true); + return; + } - if(Database.AddMessage(identifier, command.Member.Id, message)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Message added." - }; - await command.RespondAsync(error); - return; - } - else - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Failed adding the message to the database." - }; - await command.RespondAsync(error); - return; - } - } - } + if (Database.AddMessage(identifier, command.Member.Id, message)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Message added." + }, true); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed adding the message to the database." + }, true); + } + } } \ No newline at end of file diff --git a/SupportChild/Commands/AddStaffCommand.cs b/SupportChild/Commands/AddStaffCommand.cs index 03f5948..f0e48ea 100644 --- a/SupportChild/Commands/AddStaffCommand.cs +++ b/SupportChild/Commands/AddStaffCommand.cs @@ -1,96 +1,67 @@ using System; -using System.Linq; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; using MySql.Data.MySqlClient; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class AddStaffCommand : ApplicationCommandModule { - public class AddStaffCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("addstaff", "Adds a new staff member.")] + public async Task OnExecute(InteractionContext command, [Option("User", "User to add to staff.")] DiscordUser user) { - [Command("addstaff")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + DiscordMember staffMember = null; + try { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "addstaff")) + staffMember = user == null ? command.Member : await command.Guild.GetMemberAsync(user.Id); + + if (staffMember == null) { - DiscordEmbed error = new DiscordEmbedBuilder + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the addstaff command but did not have permission."); + Description = "Could not find that user in this server." + }, true); return; } - - ulong userID; - string[] parsedArgs = Utilities.ParseIDs(commandArgs); - - if (!parsedArgs.Any()) + } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { - userID = command.Member.Id; - } - else if (!ulong.TryParse(parsedArgs[0], out userID)) + Color = DiscordColor.Red, + Description = "Could not find that user in this server." + }, true); + return; + } + + await using MySqlConnection c = Database.GetConnection(); + MySqlCommand cmd = Database.IsStaff(staffMember.Id) ? new MySqlCommand(@"UPDATE staff SET name = @name WHERE user_id = @user_id", c) : new MySqlCommand(@"INSERT INTO staff (user_id, name) VALUES (@user_id, @name);", c); + + c.Open(); + cmd.Parameters.AddWithValue("@user_id", staffMember.Id); + cmd.Parameters.AddWithValue("@name", staffMember.DisplayName); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = staffMember.Mention + " was added to staff." + }); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } - - DiscordMember member; - try - { - member = await command.Guild.GetMemberAsync(userID); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not find user on this server)" - }; - await command.RespondAsync(error); - return; - } - - using (MySqlConnection c = Database.GetConnection()) - { - MySqlCommand cmd = Database.IsStaff(userID) ? new MySqlCommand(@"UPDATE staff SET name = @name WHERE user_id = @user_id", c) : new MySqlCommand(@"INSERT INTO staff (user_id, name) VALUES (@user_id, @name);", c); - - c.Open(); - cmd.Parameters.AddWithValue("@user_id", userID); - cmd.Parameters.AddWithValue("@name", member.DisplayName); - cmd.ExecuteNonQuery(); - cmd.Dispose(); - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = member.Mention + " was added to staff." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = member.Mention + " was added to staff.\n", - }; - await logChannel.SendMessageAsync(logMessage); - } - } + Color = DiscordColor.Green, + Description = staffMember.Mention + " was added to staff.\n" + }); } } } \ No newline at end of file diff --git a/SupportChild/Commands/AdminCommands.cs b/SupportChild/Commands/AdminCommands.cs new file mode 100644 index 0000000..bf90847 --- /dev/null +++ b/SupportChild/Commands/AdminCommands.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +[SlashCommandGroup("admin", "Administrative commands.")] +public class AdminCommands : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("listinvalid", "List tickets which channels have been deleted. Use /admin unsetticket to remove them.")] + public async Task ListInvalid(InteractionContext command) + { + if (!Database.TryGetOpenTickets(out List openTickets)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Could not get any open tickets from database." + }, true); + } + + // Get all channels in all guilds the bot is part of + List allChannels = new List(); + foreach (KeyValuePair guild in SupportChild.discordClient.Guilds) + { + try + { + allChannels.AddRange(await guild.Value.GetChannelsAsync()); + } + catch (Exception) { /*ignored*/ } + } + + // Check which tickets channels no longer exist + List listItems = new List(); + foreach (Database.Ticket ticket in openTickets) + { + if (allChannels.All(channel => channel.Id != ticket.channelID)) + { + listItems.Add("ID: **" + ticket.id.ToString("00000") + ":** <#" + ticket.channelID + ">\n"); + } + } + + if (listItems.Count == 0) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "All tickets are valid!" + }, true); + return; + } + + List embeds = new List(); + foreach (string message in Utilities.ParseListIntoMessages(listItems)) + { + embeds.Add(new DiscordEmbedBuilder + { + Title = "Invalid tickets:", + Color = DiscordColor.Red, + Description = message + }); + } + + // Add the footers + for (int i = 0; i < embeds.Count; i++) + { + embeds[i].Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = $"Page {i + 1} / {embeds.Count}" + }; + } + + List listPages = new List(); + foreach (DiscordEmbedBuilder embed in embeds) + { + listPages.Add(new Page("", embed)); + } + + await command.Interaction.SendPaginatedResponseAsync(true, command.User, listPages); + } + + [SlashRequireGuild] + [SlashCommand("setticket", "Turns a channel into a ticket WARNING: Anyone will be able to delete the channel using /close.")] + public async Task SetTicket(InteractionContext command, [Option("User", "(Optional) The owner of the ticket.")] DiscordUser user = null) + { + // Check if ticket exists in the database + if (Database.IsOpenTicket(command.Channel.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is already a ticket." + }, true); + return; + } + + DiscordUser ticketUser = (user == null ? command.User : user); + + long id = Database.NewTicket(ticketUser.Id, 0, command.Channel.Id); + string ticketID = id.ToString("00000"); + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Channel has been designated ticket " + ticketID + "." + }); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = command.Channel.Mention + " has been designated ticket " + ticketID + " by " + command.Member.Mention + "." + }); + } + } + + [SlashRequireGuild] + [SlashCommand("unsetticket", "Deletes a ticket from the ticket system without deleting the channel.")] + public async Task UnsetTicket(InteractionContext command, [Option("TicketID", "(Optional) Ticket to unset. Uses the channel you are in by default.")] long ticketID = 0) + { + Database.Ticket ticket; + + if (ticketID == 0) + { + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out ticket)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket!" + }, true); + return; + } + } + else + { + // Check if ticket exists in the database + if (!Database.TryGetOpenTicketByID((uint)ticketID, out ticket)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is no ticket with this ticket ID." + }, true); + return; + } + } + + + if (Database.DeleteOpenTicket(ticket.id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Channel has been undesignated as a ticket." + }); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = command.Channel.Mention + " has been undesignated as a ticket by " + command.Member.Mention + "." + }); + } + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed removing ticket from database." + }, true); + } + } + + [SlashCommand("reload", "Reloads the bot config.")] + public async Task Reload(InteractionContext command) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Reloading bot application..." + }); + Logger.Log("Reloading bot..."); + SupportChild.Reload(); + } +} \ No newline at end of file diff --git a/SupportChild/Commands/AssignCommand.cs b/SupportChild/Commands/AssignCommand.cs index a4660f6..171760a 100644 --- a/SupportChild/Commands/AssignCommand.cs +++ b/SupportChild/Commands/AssignCommand.cs @@ -1,135 +1,102 @@ -using System.Linq; +using System; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class AssignCommand : ApplicationCommandModule { - public class AssignCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("assign", "Assigns a staff member to this ticket.")] + public async Task OnExecute(InteractionContext command, [Option("User", "(Optional) User to assign to this ticket.")] DiscordUser user = null) { - [Command("assign")] - [Description("Assigns a staff member to a ticket.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + DiscordMember member = null; + try { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "assign")) + member = user == null ? command.Member : await command.Guild.GetMemberAsync(user.Id); + + if (member == null) { - DiscordEmbed error = new DiscordEmbedBuilder + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the assign command but did not have permission."); + Description = "Could not find that user in this server." + }, true); return; } - - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } + Color = DiscordColor.Red, + Description = "Could not find that user in this server." + }, true); + return; + } - ulong staffID; - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); - - if (!parsedMessage.Any()) + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { - staffID = command.Member.Id; - } - else if (!ulong.TryParse(parsedMessage[0], out staffID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; + } - DiscordMember staffMember = null; + if (!Database.IsStaff(member.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: User is not registered as staff." + }, true); + return; + } + + if (!Database.AssignStaff(ticket, member.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed to assign " + member.Mention + " to ticket." + }, true); + return; + } + + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Assigned " + member.Mention + " to ticket." + }); + + if (Config.assignmentNotifications) + { try { - staffMember = await command.Guild.GetMemberAsync(staffID); - } - catch (NotFoundException) { } - - if (staffMember == null) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Could not find user." - }; - await command.RespondAsync(error); - return; - } - - if (!Database.IsStaff(staffMember.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: User is not registered as staff." - }; - await command.RespondAsync(error); - return; - } - - if (!Database.AssignStaff(ticket, staffID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Failed to assign " + staffMember.Mention + " to ticket." - }; - await command.RespondAsync(error); - return; - } - - DiscordEmbed feedback = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Assigned " + staffMember.Mention + " to ticket." - }; - await command.RespondAsync(feedback); - - if (Config.assignmentNotifications) - { - try - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "You have been assigned to a support ticket: " + command.Channel.Mention - }; - await staffMember.SendMessageAsync(message); - } - catch (UnauthorizedException) {} - - } - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder + await member.SendMessageAsync(new DiscordEmbedBuilder { Color = DiscordColor.Green, - Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); + Description = "You have been assigned to a support ticket: " + command.Channel.Mention + }); } + catch (UnauthorizedException) { } + } + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = member.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." + }); } } } \ No newline at end of file diff --git a/SupportChild/Commands/BlacklistCommand.cs b/SupportChild/Commands/BlacklistCommand.cs index dedf9ad..33a6262 100644 --- a/SupportChild/Commands/BlacklistCommand.cs +++ b/SupportChild/Commands/BlacklistCommand.cs @@ -1,99 +1,54 @@ using System; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class BlacklistCommand : ApplicationCommandModule { - public class BlacklistCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("blacklist", "Blacklists a user from opening tickets.")] + public async Task OnExecute(InteractionContext command, [Option("User", "User to blacklist.")] DiscordUser user) { - [Command("blacklist")] - [Description("Blacklists a user from opening tickets.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + try { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "blacklist")) + if (!Database.Blacklist(user.Id, command.User.Id)) { - DiscordEmbed error = new DiscordEmbedBuilder + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the blacklist command but did not have permission."); + Description = user.Mention + " is already blacklisted." + }, true); return; } - string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString); - foreach (string parsedArg in parsedArgs) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - if (ulong.TryParse(parsedArg, out ulong userId)) + Color = DiscordColor.Green, + Description = "Blacklisted " + user.Mention + "." + }, true); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { - DiscordUser blacklistedUser = null; - try - { - blacklistedUser = await command.Client.GetUserAsync(userId); - } - catch (NotFoundException) { } - - if (blacklistedUser == null) - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Could not find user." - }; - await command.RespondAsync(message); - continue; - } - - try - { - if (!Database.Blacklist(blacklistedUser.Id, command.User.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = blacklistedUser.Mention + " is already blacklisted." - }; - await command.RespondAsync(error); - continue; - } - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Blacklisted " + blacklistedUser.Mention + "." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = blacklistedUser.Mention + " was blacklisted from opening tickets by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - catch (Exception) - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error occured while blacklisting " + blacklistedUser.Mention + "." - }; - await command.RespondAsync(message); - throw; - } - } + Color = DiscordColor.Green, + Description = user.Mention + " was blacklisted from opening tickets by " + command.Member.Mention + "." + }); } } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error occured while blacklisting " + user.Mention + "." + }, true); + throw; + } } } \ No newline at end of file diff --git a/SupportChild/Commands/CloseCommand.cs b/SupportChild/Commands/CloseCommand.cs index 51e5324..059d34f 100644 --- a/SupportChild/Commands/CloseCommand.cs +++ b/SupportChild/Commands/CloseCommand.cs @@ -2,117 +2,133 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus; using DSharpPlus.Entities; using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class CloseCommand : ApplicationCommandModule { - public class CloseCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("close", "Closes a ticket.")] + public async Task OnExecute(InteractionContext command) { - [Command("close")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket _)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "close")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the close command but did not have permission."); - return; - } + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }); + return; + } - ulong channelID = command.Channel.Id; - string channelName = command.Channel.Name; - - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(channelID, out Database.Ticket ticket)) + DiscordInteractionResponseBuilder confirmation = new DiscordInteractionResponseBuilder() + .AddEmbed(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } + Color = DiscordColor.Cyan, + Description = "Are you sure you wish to close this ticket? You cannot re-open it again later." + }) + .AddComponents(new DiscordButtonComponent(ButtonStyle.Danger, "supportboi_closeconfirm", "Confirm")); + + + await command.CreateResponseAsync(confirmation); + } + + public static async Task OnConfirmed(DiscordInteraction interaction) + { + await interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate); + ulong channelID = interaction.Channel.Id; + string channelName = interaction.Channel.Name; + + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(channelID, out Database.Ticket ticket)) + { + await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + })); + return; + } + + // Build transcript + try + { + await Transcriber.ExecuteAsync(interaction.Channel.Id, ticket.id); + } + catch (Exception e) + { + Logger.Error("Exception occured when trying to save transcript while closing ticket: " + e); + await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "ERROR: Could not save transcript file. Aborting..." + })); + return; + } + + // Log it if the log channel exists + DiscordChannel logChannel = interaction.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + DiscordEmbed embed = new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Ticket " + ticket.id.ToString("00000") + " closed by " + interaction.User.Mention + ".\n", + Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } + }; + + await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read); + DiscordMessageBuilder message = new DiscordMessageBuilder(); + message.WithEmbed(embed); + message.WithFiles(new Dictionary { { Transcriber.GetFilename(ticket.id), file } }); + + await logChannel.SendMessageAsync(message); + } + + if (Config.closingNotifications) + { + DiscordEmbed embed = new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Ticket " + ticket.id.ToString("00000") + " which you opened has now been closed, check the transcript for more info.\n", + Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } + }; - // Build transcript try { - await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); + DiscordMember staffMember = await interaction.Guild.GetMemberAsync(ticket.creatorID); + await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read); + + DiscordMessageBuilder message = new DiscordMessageBuilder(); + message.WithEmbed(embed); + message.WithFiles(new Dictionary { { Transcriber.GetFilename(ticket.id), file } }); + + await staffMember.SendMessageAsync(message); } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "ERROR: Could not save transcript file. Aborting..." - }; - await command.RespondAsync(error); - throw; - } - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed embed = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket " + ticket.id.ToString("00000") + " closed by " + command.Member.Mention + ".\n", - Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } - }; - - using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) - { - DiscordMessageBuilder message = new DiscordMessageBuilder(); - message.WithEmbed(embed); - message.WithFiles(new Dictionary() { { Transcriber.GetFilename(ticket.id), file } }); - - await logChannel.SendMessageAsync(message); - } - } - - if (Config.closingNotifications) - { - DiscordEmbed embed = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket " + ticket.id.ToString("00000") + " which you opened has now been closed, check the transcript for more info.\n", - Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } - }; - - try - { - DiscordMember staffMember = await command.Guild.GetMemberAsync(ticket.creatorID); - - using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) - { - DiscordMessageBuilder message = new DiscordMessageBuilder(); - message.WithEmbed(embed); - message.WithFiles(new Dictionary() { { Transcriber.GetFilename(ticket.id), file } }); - - await staffMember.SendMessageAsync(message); - } - } - catch (NotFoundException) { } - catch (UnauthorizedException) { } - } - - Database.ArchiveTicket(ticket); - - // Delete the channel and database entry - await command.Channel.DeleteAsync("Ticket closed."); - - Database.DeleteOpenTicket(ticket.id); + catch (NotFoundException) { } + catch (UnauthorizedException) { } } + + Database.ArchiveTicket(ticket); + + await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Channel will be deleted in 3 seconds..." + })); + + + await Task.Delay(3000); + + // Delete the channel and database entry + await interaction.Channel.DeleteAsync("Ticket closed."); + + Database.DeleteOpenTicket(ticket.id); } } \ No newline at end of file diff --git a/SupportChild/Commands/CreateButtonPanelCommand.cs b/SupportChild/Commands/CreateButtonPanelCommand.cs new file mode 100644 index 0000000..15ee739 --- /dev/null +++ b/SupportChild/Commands/CreateButtonPanelCommand.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus; +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +public class CreateButtonPanelCommand : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("createbuttonpanel", "Creates a series of buttons which users can use to open new tickets in specific categories.")] + public async Task OnExecute(InteractionContext command) + { + DiscordMessageBuilder builder = new DiscordMessageBuilder().WithContent(" "); + List verifiedCategories = await Utilities.GetVerifiedChannels(); + + if (verifiedCategories.Count == 0) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: No registered categories found." + }, true); + return; + } + + verifiedCategories = verifiedCategories.OrderBy(x => x.name).ToList(); + + int nrOfButtons = 0; + for (int nrOfButtonRows = 0; nrOfButtonRows < 5 && nrOfButtons < verifiedCategories.Count; nrOfButtonRows++) + { + List buttonRow = new List(); + + for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < verifiedCategories.Count; nrOfButtons++) + { + buttonRow.Add(new DiscordButtonComponent(ButtonStyle.Primary, "supportboi_newticketbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name)); + } + builder.AddComponents(buttonRow); + } + + await command.Channel.SendMessageAsync(builder); + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Successfully created message, make sure to run this command again if you add new categories to the bot." + }, true); + } + + public static async Task OnButtonUsed(DiscordInteraction interaction) + { + await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral()); + + if (!ulong.TryParse(interaction.Data.CustomId.Replace("supportboi_newticketbutton ", ""), out ulong categoryID) || categoryID == 0) + { + Logger.Warn("Invalid ID: " + interaction.Data.CustomId.Replace("supportboi_newticketbutton ", "")); + return; + } + + (bool success, string message) = await NewCommand.OpenNewTicket(interaction.User.Id, interaction.ChannelId, categoryID); + + if (success) + { + await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = message + })); + } + else + { + await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = message + })); + } + } +} \ No newline at end of file diff --git a/SupportChild/Commands/CreateSelectionBoxPanelCommand.cs b/SupportChild/Commands/CreateSelectionBoxPanelCommand.cs new file mode 100644 index 0000000..395d1e5 --- /dev/null +++ b/SupportChild/Commands/CreateSelectionBoxPanelCommand.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using DSharpPlus; +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +public class CreateSelectionBoxPanelCommand : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("createselectionboxpanel", "Creates a selection box which users can use to open new tickets in specific categories.")] + public async Task OnExecute(InteractionContext command, [Option("Message", "(Optional) The message to show in the selection box.")] string message = null) + { + DiscordMessageBuilder builder = new DiscordMessageBuilder() + .WithContent(" ") + .AddComponents(await GetSelectComponents(command, message ?? "Open new ticket...")); + + await command.Channel.SendMessageAsync(builder); + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Successfully created message, make sure to run this command again if you add new categories to the bot." + }, true); + } + + public static async Task> GetSelectComponents(InteractionContext command, string placeholder) + { + List verifiedCategories = await Utilities.GetVerifiedChannels(); + + if (verifiedCategories.Count == 0) return new List(); + + verifiedCategories = verifiedCategories.OrderBy(x => x.name).ToList(); + List selectionComponents = new List(); + int selectionOptions = 0; + for (int selectionBoxes = 0; selectionBoxes < 5 && selectionOptions < verifiedCategories.Count; selectionBoxes++) + { + List categoryOptions = new List(); + + for (; selectionOptions < 25 * (selectionBoxes + 1) && selectionOptions < verifiedCategories.Count; selectionOptions++) + { + categoryOptions.Add(new DiscordSelectComponentOption(verifiedCategories[selectionOptions].name, verifiedCategories[selectionOptions].id.ToString())); + } + selectionComponents.Add(new DiscordSelectComponent("supportboi_newticketselector" + selectionBoxes, placeholder, categoryOptions, false, 0, 1)); + } + + return selectionComponents; + } + + public static async Task OnSelectionMenuUsed(DiscordInteraction interaction) + { + if (interaction.Data.Values == null || interaction.Data.Values.Length <= 0) return; + + if (!ulong.TryParse(interaction.Data.Values[0], out ulong categoryID) || categoryID == 0) return; + + await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral()); + + (bool success, string message) = await NewCommand.OpenNewTicket(interaction.User.Id, interaction.ChannelId, categoryID); + + if (success) + { + await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = message + }).AsEphemeral()); + } + else + { + await interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = message + }).AsEphemeral()); + } + } +} \ No newline at end of file diff --git a/SupportChild/Commands/ListAssignedCommand.cs b/SupportChild/Commands/ListAssignedCommand.cs index 351df6c..b9ce36f 100644 --- a/SupportChild/Commands/ListAssignedCommand.cs +++ b/SupportChild/Commands/ListAssignedCommand.cs @@ -1,76 +1,63 @@ using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.Interactivity; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class ListAssignedCommand : ApplicationCommandModule { - public class ListAssignedCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("listassigned", "Lists tickets assigned to a user.")] + public async Task OnExecute(InteractionContext command, [Option("User", "(Optional) User to list tickets for.")] DiscordUser user = null) { - [Command("listassigned")] - [Aliases("la")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + DiscordUser listUser = user == null ? command.User : user; + + if (!Database.TryGetAssignedTickets(listUser.Id, out List assignedTickets)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "listassigned")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the listassigned command but did not have permission."); - return; - } - - ulong staffID; - string[] parsedIDs = Utilities.ParseIDs(command.RawArgumentString); - - if (!parsedIDs.Any()) - { - staffID = command.Member.Id; - } - else if (!ulong.TryParse(parsedIDs[0], out staffID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } - - if (!Database.TryGetAssignedTickets(staffID, out List assignedTickets)) - { - DiscordEmbed error = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Red) - .WithDescription("User does not have any assigned tickets."); - await command.RespondAsync(error); - return; - } - - List listItems = new List(); - foreach (Database.Ticket ticket in assignedTickets) - { - listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); - } - - LinkedList messages = Utilities.ParseListIntoMessages(listItems); - foreach (string message in messages) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Assigned tickets: ") - .WithColor(DiscordColor.Green) - .WithDescription(message); - await command.RespondAsync(channelInfo); - } - + Color = DiscordColor.Red, + Description = "User does not have any assigned tickets." + }); + return; } + + List listItems = new List(); + foreach (Database.Ticket ticket in assignedTickets) + { + listItems.Add("**" + ticket.DiscordRelativeTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); + } + + List embeds = new List(); + foreach (string message in Utilities.ParseListIntoMessages(listItems)) + { + embeds.Add(new DiscordEmbedBuilder + { + Title = "Assigned tickets: ", + Color = DiscordColor.Green, + Description = message + }); + } + + // Add the footers + for (int i = 0; i < embeds.Count; i++) + { + embeds[i].Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = $"Page {i + 1} / {embeds.Count}" + }; + } + + List listPages = new List(); + foreach (DiscordEmbedBuilder embed in embeds) + { + listPages.Add(new Page("", embed)); + } + + await command.Interaction.SendPaginatedResponseAsync(true, command.User, listPages); } } \ No newline at end of file diff --git a/SupportChild/Commands/ListCommand.cs b/SupportChild/Commands/ListCommand.cs index 3916ed4..e2811b5 100644 --- a/SupportChild/Commands/ListCommand.cs +++ b/SupportChild/Commands/ListCommand.cs @@ -1,101 +1,99 @@ using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.Interactivity; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class ListCommand : ApplicationCommandModule { - public class ListCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("list", "Lists tickets opened by a user.")] + public async Task OnExecute(InteractionContext command, [Option("User", "(Optional) The user to get tickets by.")] DiscordUser user = null) { - [Command("list")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + DiscordUser listUser = user == null ? command.User : user; + + List openEmbeds = new List(); + if (Database.TryGetOpenTickets(listUser.Id, out List openTickets)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "list")) + List listItems = new List(); + foreach (Database.Ticket ticket in openTickets) { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the list command but did not have permission."); - return; + listItems.Add("**" + ticket.DiscordRelativeTime() + ":** <#" + ticket.channelID + ">\n"); } - ulong userID; - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); - - if (!parsedMessage.Any()) + foreach (string message in Utilities.ParseListIntoMessages(listItems)) { - userID = command.Member.Id; - } - else if (!ulong.TryParse(parsedMessage[0], out userID)) - { - DiscordEmbed error = new DiscordEmbedBuilder + openEmbeds.Add(new DiscordEmbedBuilder { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; + Color = DiscordColor.Green, + Description = message + }); } - if (Database.TryGetOpenTickets(userID, out List openTickets)) + // Add the titles + for (int i = 0; i < openEmbeds.Count; i++) { - List listItems = new List(); - foreach (Database.Ticket ticket in openTickets) - { - listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + ">\n"); - } - - LinkedList messages = Utilities.ParseListIntoMessages(listItems); - foreach (string message in messages) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Open tickets: ") - .WithColor(DiscordColor.Green) - .WithDescription(message); - await command.RespondAsync(channelInfo); - } - } - else - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Green) - .WithDescription("User does not have any open tickets."); - await command.RespondAsync(channelInfo); - } - - if (Database.TryGetClosedTickets(userID, out List closedTickets)) - { - List listItems = new List(); - foreach (Database.Ticket ticket in closedTickets) - { - listItems.Add("**" + ticket.FormattedCreatedTime() + ":** Ticket " + ticket.id.ToString("00000") + "\n"); - } - - LinkedList messages = Utilities.ParseListIntoMessages(listItems); - foreach (string message in messages) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Closed tickets: ") - .WithColor(DiscordColor.Red) - .WithDescription(message); - await command.RespondAsync(channelInfo); - } - } - else - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Red) - .WithDescription("User does not have any closed tickets."); - await command.RespondAsync(channelInfo); + openEmbeds[i].Title = $"Open tickets ({i + 1}/{openEmbeds.Count})"; } } + + List closedEmbeds = new List(); + if (Database.TryGetClosedTickets(listUser.Id, out List closedTickets)) + { + List listItems = new List(); + foreach (Database.Ticket ticket in closedTickets) + { + listItems.Add("**" + ticket.DiscordRelativeTime() + ":** Ticket " + ticket.id.ToString("00000") + "\n"); + } + + foreach (string message in Utilities.ParseListIntoMessages(listItems)) + { + closedEmbeds.Add(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = message + }); + } + + // Add the titles + for (int i = 0; i < closedEmbeds.Count; i++) + { + closedEmbeds[i].Title = $"Closed tickets ({i + 1}/{closedEmbeds.Count})"; + } + } + + // Merge the embed lists and add the footers + List embeds = new List(); + embeds.AddRange(openEmbeds); + embeds.AddRange(closedEmbeds); + for (int i = 0; i < embeds.Count; i++) + { + embeds[i].Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = $"Page {i + 1} / {embeds.Count}" + }; + } + + if (embeds.Count == 0) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Cyan, + Description = "User does not have any open or closed tickets." + }); + return; + } + + List listPages = new List(); + foreach (DiscordEmbedBuilder embed in embeds) + { + listPages.Add(new Page("", embed)); + } + + await command.Interaction.SendPaginatedResponseAsync(true, command.User, listPages); } } \ No newline at end of file diff --git a/SupportChild/Commands/ListOldestCommand.cs b/SupportChild/Commands/ListOldestCommand.cs deleted file mode 100644 index 394b8d0..0000000 --- a/SupportChild/Commands/ListOldestCommand.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; - -namespace SupportChild.Commands -{ - public class ListOldestCommand : BaseCommandModule - { - [Command("listoldest")] - [Aliases("lo")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "listoldest")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the listoldest command but did not have permission."); - return; - } - - int listLimit = 20; - if (!string.IsNullOrEmpty(command.RawArgumentString?.Trim() ?? "")) - { - if (!int.TryParse(command.RawArgumentString?.Trim(), out listLimit) || listLimit < 5 || listLimit > 100) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid list amount. (Must be integer between 5 and 100)" - }; - await command.RespondAsync(error); - return; - } - } - - if (!Database.TryGetOldestTickets(command.Member.Id, out List openTickets, listLimit)) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Red) - .WithDescription("Could not fetch any open tickets."); - await command.RespondAsync(channelInfo); - return; - } - - List listItems = new List(); - foreach (Database.Ticket ticket in openTickets) - { - listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); - } - - LinkedList messages = Utilities.ParseListIntoMessages(listItems); - foreach (string message in messages) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("The " + openTickets.Count + " oldest open tickets: ") - .WithColor(DiscordColor.Green) - .WithDescription(message?.Trim()); - await command.RespondAsync(channelInfo); - } - } - } -} \ No newline at end of file diff --git a/SupportChild/Commands/ListOpen.cs b/SupportChild/Commands/ListOpen.cs new file mode 100644 index 0000000..7775e17 --- /dev/null +++ b/SupportChild/Commands/ListOpen.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using DSharpPlus.Entities; +using DSharpPlus.Interactivity; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +public class ListOpen : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("listopen", "Lists all open tickets, oldest first.")] + public async Task OnExecute(InteractionContext command) + { + if (!Database.TryGetOpenTickets(out List openTickets)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Could not fetch any open tickets." + }); + return; + } + + List listItems = new List(); + foreach (Database.Ticket ticket in openTickets) + { + listItems.Add("**" + ticket.DiscordRelativeTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); + } + + List embeds = new List(); + foreach (string message in Utilities.ParseListIntoMessages(listItems)) + { + embeds.Add(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = message + }); + } + + // Add the footers + for (int i = 0; i < embeds.Count; i++) + { + embeds[i].Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = $"Page {i + 1} / {embeds.Count}" + }; + } + + List listPages = new List(); + foreach (DiscordEmbedBuilder embed in embeds) + { + listPages.Add(new Page("", embed)); + } + + await command.Interaction.SendPaginatedResponseAsync(true, command.User, listPages); + } +} \ No newline at end of file diff --git a/SupportChild/Commands/ListUnassignedCommand.cs b/SupportChild/Commands/ListUnassignedCommand.cs index 19236cf..bb0bba7 100644 --- a/SupportChild/Commands/ListUnassignedCommand.cs +++ b/SupportChild/Commands/ListUnassignedCommand.cs @@ -1,55 +1,61 @@ using System.Collections.Generic; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.Interactivity; +using DSharpPlus.Interactivity.Extensions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class ListUnassignedCommand : ApplicationCommandModule { - public class ListUnassignedCommand : BaseCommandModule - { - [Command("listunassigned")] - [Aliases("lu")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "listunassigned")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the listunassigned command but did not have permission."); - return; - } + [SlashRequireGuild] + [SlashCommand("listunassigned", "Lists unassigned tickets.")] + public async Task OnExecute(InteractionContext command) + { + if (!Database.TryGetAssignedTickets(0, out List unassignedTickets)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "There are no unassigned tickets." + }); + return; + } - if (!Database.TryGetAssignedTickets(0, out List unassignedTickets)) - { - DiscordEmbed response = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Green) - .WithDescription("There are no unassigned tickets."); - await command.RespondAsync(response); - } + List listItems = new List(); + foreach (Database.Ticket ticket in unassignedTickets) + { + listItems.Add("**" + ticket.DiscordRelativeTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); + } - List listItems = new List(); - foreach (Database.Ticket ticket in unassignedTickets) - { - listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); - } + List embeds = new List(); + foreach (string message in Utilities.ParseListIntoMessages(listItems)) + { + embeds.Add(new DiscordEmbedBuilder + { + Title = "Unassigned tickets: ", + Color = DiscordColor.Green, + Description = message + }); + } - LinkedList messages = Utilities.ParseListIntoMessages(listItems); - foreach (string message in messages) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Unassigned tickets: ") - .WithColor(DiscordColor.Green) - .WithDescription(message?.Trim()); - await command.RespondAsync(channelInfo); - } - } - } + // Add the footers + for (int i = 0; i < embeds.Count; i++) + { + embeds[i].Footer = new DiscordEmbedBuilder.EmbedFooter + { + Text = $"Page {i + 1} / {embeds.Count}" + }; + } + + List listPages = new List(); + foreach (DiscordEmbedBuilder embed in embeds) + { + listPages.Add(new Page("", embed)); + } + + await command.Interaction.SendPaginatedResponseAsync(true, command.User, listPages); + } } \ No newline at end of file diff --git a/SupportChild/Commands/MoveCommand.cs b/SupportChild/Commands/MoveCommand.cs index 4ef0737..e81cf70 100644 --- a/SupportChild/Commands/MoveCommand.cs +++ b/SupportChild/Commands/MoveCommand.cs @@ -2,103 +2,82 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class MoveCommand : ApplicationCommandModule { - public class MoveCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("move", "Moves a ticket to another category.")] + public async Task OnExecute(InteractionContext command, [Option("Category", "The category to move the ticket to. Only has to be the beginning of the name.")] string category) { - [Command("move")] - [Description("Moves a ticket to another category.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket _)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "move")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the move command but did not have permission."); - return; - } - - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } - - if (string.IsNullOrEmpty(command.RawArgumentString)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: No category provided." - }; - await command.RespondAsync(error); - return; - } - - IReadOnlyList channels = await command.Guild.GetChannelsAsync(); - IEnumerable categories = channels.Where(x => x.IsCategory); - DiscordChannel category = categories.FirstOrDefault(x => x.Name.StartsWith(command.RawArgumentString.Trim(), StringComparison.OrdinalIgnoreCase)); - - if (category == null) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Could not find a category by that name." - }; - await command.RespondAsync(error); - return; - } - - if (command.Channel.Id == category.Id) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: The ticket is already in that category." - }; - await command.RespondAsync(error); - return; - } - - try - { - await command.Channel.ModifyAsync(modifiedAttributes => modifiedAttributes.Parent = category); - } - catch (UnauthorizedException) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Not authorized to move this ticket to that category." - }; - await command.RespondAsync(error); - return; - } - - DiscordEmbed feedback = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket was moved to " + category.Mention - }; - await command.RespondAsync(feedback); + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; } + + if (string.IsNullOrEmpty(category)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: No category provided." + }, true); + return; + } + + IReadOnlyList channels = await command.Guild.GetChannelsAsync(); + IEnumerable categories = channels.Where(x => x.IsCategory); + DiscordChannel categoryChannel = categories.FirstOrDefault(x => x.Name.StartsWith(category.Trim(), StringComparison.OrdinalIgnoreCase)); + + if (categoryChannel == null) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Could not find a category by that name." + }, true); + return; + } + + if (command.Channel.Id == categoryChannel.Id) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: The ticket is already in that category." + }, true); + return; + } + + try + { + await command.Channel.ModifyAsync(modifiedAttributes => modifiedAttributes.Parent = categoryChannel); + } + catch (UnauthorizedException) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Not authorized to move this ticket to that category." + }, true); + return; + } + + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Ticket was moved to " + categoryChannel.Mention + }); } } \ No newline at end of file diff --git a/SupportChild/Commands/NewCommand.cs b/SupportChild/Commands/NewCommand.cs index 1345a00..0b77184 100644 --- a/SupportChild/Commands/NewCommand.cs +++ b/SupportChild/Commands/NewCommand.cs @@ -1,150 +1,276 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class NewCommand : ApplicationCommandModule { - public class NewCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("new", "Opens a new ticket.")] + public async Task OnExecute(InteractionContext command) { - [Command("new")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + List verifiedCategories = await Utilities.GetVerifiedChannels(); + switch (verifiedCategories.Count) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "new")) - { - DiscordEmbed error = new DiscordEmbedBuilder + case 0: + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the new command but did not have permission."); + Description = "Error: No registered categories found." + }, true); return; - } + case 1: + await command.DeferAsync(true); + (bool success, string message) = await OpenNewTicket(command.User.Id, command.Channel.Id, verifiedCategories[0].id); - // Check if user is blacklisted - if (Database.IsBlacklisted(command.User.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder + if (success) { - Color = DiscordColor.Red, - Description = "You are banned from opening tickets." - }; - await command.RespondAsync(error); - return; - } - - if (Database.IsOpenTicket(command.Channel.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder + await command.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = message + }).AsEphemeral()); + } + else { - Color = DiscordColor.Red, - Description = "You cannot use this command in a ticket channel." - }; - await command.RespondAsync(error); + await command.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = message + }).AsEphemeral()); + } return; - } - - DiscordChannel category = command.Guild.GetChannel(Config.ticketCategory); - DiscordChannel ticketChannel; - - try - { - ticketChannel = await command.Guild.CreateChannelAsync("ticket", ChannelType.Text, category); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder + default: + if (Config.newCommandUsesSelector) { - Color = DiscordColor.Red, - Description = "Error occured while creating ticket, " + command.Member.Mention + - "!\nIs the channel limit reached in the server or ticket category?" - }; - await command.RespondAsync(error); - return; - } - - if (ticketChannel == null) - { - DiscordEmbed error = new DiscordEmbedBuilder + await CreateSelector(command, verifiedCategories); + } + else { - Color = DiscordColor.Red, - Description = "Error occured while creating ticket, " + command.Member.Mention + - "!\nIs the channel limit reached in the server or ticket category?" - }; - await command.RespondAsync(error); + await CreateButtons(command, verifiedCategories); + } return; - } + } + } - ulong staffID = 0; - if (Config.randomAssignment) + public static async Task CreateButtons(InteractionContext command, List verifiedCategories) + { + DiscordInteractionResponseBuilder builder = new DiscordInteractionResponseBuilder().WithContent(" "); + int nrOfButtons = 0; + for (int nrOfButtonRows = 0; nrOfButtonRows < 5 && nrOfButtons < verifiedCategories.Count; nrOfButtonRows++) + { + List buttonRow = new List(); + + for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < verifiedCategories.Count; nrOfButtons++) { - staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0; + buttonRow.Add(new DiscordButtonComponent(ButtonStyle.Primary, "supportboi_newcommandbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name)); } + builder.AddComponents(buttonRow); + } - long id = Database.NewTicket(command.Member.Id, staffID, ticketChannel.Id); - string ticketID = id.ToString("00000"); + await command.CreateResponseAsync(builder.AsEphemeral()); + } + + public static async Task CreateSelector(InteractionContext command, List verifiedCategories) + { + verifiedCategories = verifiedCategories.OrderBy(x => x.name).ToList(); + List selectionComponents = new List(); + int selectionOptions = 0; + for (int selectionBoxes = 0; selectionBoxes < 5 && selectionOptions < verifiedCategories.Count; selectionBoxes++) + { + List categoryOptions = new List(); + + for (; selectionOptions < 25 * (selectionBoxes + 1) && selectionOptions < verifiedCategories.Count; selectionOptions++) + { + categoryOptions.Add(new DiscordSelectComponentOption(verifiedCategories[selectionOptions].name, verifiedCategories[selectionOptions].id.ToString())); + } + selectionComponents.Add(new DiscordSelectComponent("supportboi_newcommandselector" + selectionBoxes, "Open new ticket...", categoryOptions, false, 0, 1)); + } + + await command.CreateResponseAsync(new DiscordInteractionResponseBuilder().AddComponents(selectionComponents).AsEphemeral()); + } + + public static async Task OnCategorySelection(DiscordInteraction interaction) + { + string stringID; + switch (interaction.Data.ComponentType) + { + case ComponentType.Button: + stringID = interaction.Data.CustomId.Replace("supportboi_newcommandbutton ", ""); + break; + case ComponentType.Select: + if (interaction.Data.Values == null || interaction.Data.Values.Length <= 0) return; + stringID = interaction.Data.Values[0]; + break; + + case ComponentType.ActionRow: + case ComponentType.FormInput: + default: + return; + } + + if (!ulong.TryParse(stringID, out ulong categoryID) || categoryID == 0) return; + + await interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate, new DiscordInteractionResponseBuilder().AsEphemeral()); + + (bool success, string message) = await OpenNewTicket(interaction.User.Id, interaction.ChannelId, categoryID); + + if (success) + { + await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = message + })); + } + else + { + await interaction.EditOriginalResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = message + })); + } + } + + public static async Task<(bool, string)> OpenNewTicket(ulong userID, ulong commandChannelID, ulong categoryID) + { + // Check if user is blacklisted + if (Database.IsBlacklisted(userID)) + { + return (false, "You are banned from opening tickets."); + } + + if (Database.IsOpenTicket(commandChannelID)) + { + return (false, "You cannot use this command in a ticket channel."); + } + + if (!Database.IsStaff(userID) && Database.TryGetOpenTickets(userID, out List ownTickets) && ownTickets.Count >= Config.ticketLimit) + { + return (false, "You have reached the limit for maximum open tickets."); + } + + DiscordChannel category = null; + try + { + category = await SupportChild.discordClient.GetChannelAsync(categoryID); + } + catch (Exception) { /*ignored*/ } + + if (category == null) + { + return (false, "Error: Could not find the category to place the ticket in."); + } + + DiscordMember member = null; + try + { + member = await category.Guild.GetMemberAsync(userID); + } + catch (Exception) { /*ignored*/ } + + if (member == null) + { + return (false, "Error: Could not find you on the Discord server."); + } + + DiscordChannel ticketChannel = null; + + try + { + ticketChannel = await category.Guild.CreateChannelAsync("ticket", ChannelType.Text, category); + } + catch (Exception) { /* ignored */ } + + if (ticketChannel == null) + { + return (false, "Error occured while creating ticket, " + member.Mention + + "!\nIs the channel limit reached in the server or ticket category?"); + } + + ulong staffID = 0; + if (Config.randomAssignment) + { + staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0; + } + + long id = Database.NewTicket(member.Id, staffID, ticketChannel.Id); + string ticketID = id.ToString("00000"); + + try + { await ticketChannel.ModifyAsync(modifiedAttributes => modifiedAttributes.Name = "ticket-" + ticketID); - await ticketChannel.AddOverwriteAsync(command.Member, Permissions.AccessChannels, Permissions.None); + } + catch (DiscordException e) + { + Logger.Error("Exception occurred trying to modify channel: " + e); + Logger.Error("JsomMessage: " + e.JsonMessage); + } - await ticketChannel.SendMessageAsync("Hello, " + command.Member.Mention + "!\n" + Config.welcomeMessage); + try + { + await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels); + } + catch (DiscordException e) + { + Logger.Error("Exception occurred trying to add channel permissions: " + e); + Logger.Error("JsomMessage: " + e.JsonMessage); + } - // Refreshes the channel as changes were made to it above - ticketChannel = command.Guild.GetChannel(ticketChannel.Id); + await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage); - if (staffID != 0) + // Refreshes the channel as changes were made to it above + ticketChannel = await SupportChild.discordClient.GetChannelAsync(ticketChannel.Id); + + if (staffID != 0) + { + await ticketChannel.SendMessageAsync(new DiscordEmbedBuilder { - DiscordEmbed assignmentMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket was randomly assigned to <@" + staffID + ">." - }; - await ticketChannel.SendMessageAsync(assignmentMessage); + Color = DiscordColor.Green, + Description = "Ticket was randomly assigned to <@" + staffID + ">." + }); - if (Config.assignmentNotifications) + if (Config.assignmentNotifications) + { + try { - DiscordEmbed message = new DiscordEmbedBuilder + DiscordMember staffMember = await category.Guild.GetMemberAsync(staffID); + await staffMember.SendMessageAsync(new DiscordEmbedBuilder { Color = DiscordColor.Green, Description = "You have been randomly assigned to a newly opened support ticket: " + - ticketChannel.Mention - }; - - try - { - DiscordMember staffMember = await command.Guild.GetMemberAsync(staffID); - await staffMember.SendMessageAsync(message); - } - catch (NotFoundException) {} - catch (UnauthorizedException) {} + ticketChannel.Mention + }); + } + catch (DiscordException e) + { + Logger.Error("Exception occurred assign random staff member: " + e); + Logger.Error("JsomMessage: " + e.JsonMessage); } } + } - DiscordEmbed response = new DiscordEmbedBuilder + // Log it if the log channel exists + DiscordChannel logChannel = category.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + DiscordEmbed logMessage = new DiscordEmbedBuilder { Color = DiscordColor.Green, - Description = "Ticket opened, " + command.Member.Mention + "!\n" + ticketChannel.Mention + Description = "Ticket " + ticketChannel.Mention + " opened by " + member.Mention + ".\n", + Footer = new DiscordEmbedBuilder.EmbedFooter { Text = "Ticket " + ticketID } }; - await command.RespondAsync(response); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket " + ticketChannel.Mention + " opened by " + command.Member.Mention + ".\n", - Footer = new DiscordEmbedBuilder.EmbedFooter {Text = "Ticket " + ticketID} - }; - await logChannel.SendMessageAsync(logMessage); - } + await logChannel.SendMessageAsync(logMessage); } + + return (true, "Ticket opened, " + member.Mention + "!\n" + ticketChannel.Mention); } } \ No newline at end of file diff --git a/SupportChild/Commands/RandomAssignCommand.cs b/SupportChild/Commands/RandomAssignCommand.cs index 7b2a3e3..36d633d 100644 --- a/SupportChild/Commands/RandomAssignCommand.cs +++ b/SupportChild/Commands/RandomAssignCommand.cs @@ -2,181 +2,138 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Exceptions; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; using Microsoft.Extensions.Logging; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class RandomAssignCommand : ApplicationCommandModule { - public class RandomAssignCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("rassign", "Randomly assigns a staff member to a ticket.")] + public async Task OnExecute(InteractionContext command, [Option("Role", "(Optional) Limit the random assignment to a specific role.")] DiscordRole role = null) { - [Command("rassign")] - [Description("Randomly assigns a staff member to a ticket.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArguments) + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "rassign")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the rassign command but did not have permission."); - return; - } - - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } - - // Get a random staff member who is verified to have the correct role if applicable - DiscordMember staffMember = await GetRandomVerifiedStaffMember(command, ticket); - if (staffMember == null) - { - return; - } - - // Attempt to assign the staff member to the ticket - if (!Database.AssignStaff(ticket, staffMember.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Failed to assign " + staffMember.Mention + " to ticket." - }; - await command.RespondAsync(error); - return; - } - - // Respond that the command was successful - DiscordEmbed feedback = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Randomly assigned " + staffMember.Mention + " to ticket." - }; - await command.RespondAsync(feedback); - - // Send a notification to the staff member if applicable - if (Config.assignmentNotifications) - { - try - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "You have been randomly assigned to a support ticket: " + command.Channel.Mention - }; - await staffMember.SendMessageAsync(message); - } - catch (UnauthorizedException) {} - } - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - - private async Task GetRandomVerifiedStaffMember(CommandContext command, Database.Ticket ticket) - { - if (command.RawArguments.Any()) // An argument was provided, check if this can be parsed into a role - { - ulong roleID = 0; - - // Try to parse either discord mention or ID - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); - if (!ulong.TryParse(parsedMessage[0], out roleID)) - { - // Try to find role by name - roleID = Utilities.GetRoleByName(command.Guild, command.RawArgumentString)?.Id ?? 0; - } - - // Check if a role was found - if (roleID == 0) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Could not find a role by that name/ID." - }; - await command.RespondAsync(error); - return null; - } - - // Check if role rassign should override staff's active status - List staffMembers = Config.randomAssignRoleOverride - ? Database.GetAllStaff(ticket.assignedStaffID) - : Database.GetActiveStaff(ticket.assignedStaffID); - - // Randomize the list before checking for roles in order to reduce number of API calls - staffMembers = Utilities.RandomizeList(staffMembers); - - // Get the first staff member that has the role - foreach (Database.StaffMember sm in staffMembers) - { - try - { - DiscordMember verifiedMember = await command.Guild.GetMemberAsync(sm.userID); - if (verifiedMember?.Roles?.Any(role => role.Id == roleID) ?? false) - { - return verifiedMember; - } - } - catch (Exception e) - { - command.Client.Logger.Log(LogLevel.Information, e, "Error occured trying to find a staff member in the rassign command."); - } - } - } - else // No role was specified, any active staff will be picked - { - Database.StaffMember staffEntry = Database.GetRandomActiveStaff(ticket.assignedStaffID); - if (staffEntry == null) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: There are no other staff members to choose from." - }; - await command.RespondAsync(error); - return null; - } - - // Get the staff member from discord - try - { - return await command.Guild.GetMemberAsync(staffEntry.userID); - } - catch (NotFoundException) { } - } - - // Send a more generic error if we get to this point and still haven't found the staff member - DiscordEmbed err = new DiscordEmbedBuilder + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "Error: Could not find an applicable staff member." - }; - await command.RespondAsync(err); - return null; + Description = "Error: This channel is not a ticket." + }, true); + return; + } + + // Get a random staff member who is verified to have the correct role if applicable + DiscordMember staffMember = await GetRandomVerifiedStaffMember(command, role, ticket); + if (staffMember == null) + { + return; + } + + // Attempt to assign the staff member to the ticket + if (!Database.AssignStaff(ticket, staffMember.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed to assign " + staffMember.Mention + " to ticket." + }, true); + return; + } + + // Respond that the command was successful + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Randomly assigned " + staffMember.Mention + " to ticket." + }); + + // Send a notification to the staff member if applicable + if (Config.assignmentNotifications) + { + try + { + await staffMember.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "You have been randomly assigned to a support ticket: " + command.Channel.Mention + }); + } + catch (UnauthorizedException) { } + } + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = staffMember.Mention + " was randomly assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." + }); } } + + private static async Task GetRandomVerifiedStaffMember(InteractionContext command, DiscordRole targetRole, Database.Ticket ticket) + { + if (targetRole != null) // A role was provided + { + // Check if role rassign should override staff's active status + List staffMembers = Config.randomAssignRoleOverride + ? Database.GetAllStaff(ticket.assignedStaffID, ticket.creatorID) + : Database.GetActiveStaff(ticket.assignedStaffID, ticket.creatorID); + + // Randomize the list before checking for roles in order to reduce number of API calls + staffMembers.Shuffle(); + + // Get the first staff member that has the role + foreach (Database.StaffMember sm in staffMembers) + { + try + { + DiscordMember verifiedMember = await command.Guild.GetMemberAsync(sm.userID); + if (verifiedMember?.Roles?.Any(role => role.Id == targetRole.Id) ?? false) + { + return verifiedMember; + } + } + catch (Exception e) + { + command.Client.Logger.Log(LogLevel.Information, e, "Error occured trying to find a staff member in the rassign command."); + } + } + } + else // No role was specified, any active staff will be picked + { + Database.StaffMember staffEntry = Database.GetRandomActiveStaff(ticket.assignedStaffID, ticket.creatorID); + if (staffEntry == null) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: There are no other staff members to choose from." + }, true); + return null; + } + + // Get the staff member from discord + try + { + return await command.Guild.GetMemberAsync(staffEntry.userID); + } + catch (NotFoundException) { } + } + + // Send a more generic error if we get to this point and still haven't found the staff member + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Could not find an applicable staff member." + }, true); + return null; + } } \ No newline at end of file diff --git a/SupportChild/Commands/ReloadCommand.cs b/SupportChild/Commands/ReloadCommand.cs deleted file mode 100644 index de426c0..0000000 --- a/SupportChild/Commands/ReloadCommand.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; - -namespace SupportChild.Commands -{ - public class ReloadCommand : BaseCommandModule - { - [Command("reload")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "reload")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the reload command but did not have permission."); - return; - } - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Reloading bot application..." - }; - await command.RespondAsync(message); - Console.WriteLine("Reloading bot..."); - SupportChild.instance.Reload(); - } - } -} \ No newline at end of file diff --git a/SupportChild/Commands/RemoveCategoryCommand.cs b/SupportChild/Commands/RemoveCategoryCommand.cs new file mode 100644 index 0000000..0cef6a4 --- /dev/null +++ b/SupportChild/Commands/RemoveCategoryCommand.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; + +namespace SupportChild.Commands; + +public class RemoveCategoryCommand : ApplicationCommandModule +{ + [SlashRequireGuild] + [SlashCommand("removecategory", "Removes the ability for users to open tickets in a specific category.")] + public async Task OnExecute(InteractionContext command, [Option("Category", "The category to remove.")] DiscordChannel channel) + { + if (!Database.TryGetCategory(channel.Id, out Database.Category _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "That category is not registered." + }, true); + return; + } + + if (Database.RemoveCategory(channel.Id)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Category removed." + }, true); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed removing the category from the database." + }, true); + } + } +} \ No newline at end of file diff --git a/SupportChild/Commands/RemoveMessageCommand.cs b/SupportChild/Commands/RemoveMessageCommand.cs index 96794e4..fc14a0f 100644 --- a/SupportChild/Commands/RemoveMessageCommand.cs +++ b/SupportChild/Commands/RemoveMessageCommand.cs @@ -1,66 +1,41 @@ -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using DSharpPlus.Entities; using System.Threading.Tasks; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class RemoveMessageCommand : ApplicationCommandModule { - public class RemoveMessageCommand : BaseCommandModule - { - [Command("removemessage")] - [Description("Removes a message from the 'say' command.")] - public async Task OnExecute(CommandContext command, string identifier) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "removemessage")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the removemessage command but did not have permission."); - return; - } + [SlashRequireGuild] + [SlashCommand("removemessage", "Removes a message from the 'say' command.")] + public async Task OnExecute(InteractionContext command, [Option("Identifier", "The identifier word used in the /say command.")] string identifier) + { + if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is no message with that identifier." + }, true); + return; + } - if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message _)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "There is no message with that identifier." - }; - await command.RespondAsync(error); - return; - } - - if(Database.RemoveMessage(identifier)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Message removed." - }; - await command.RespondAsync(error); - return; - } - else - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Failed removing the message from the database." - }; - await command.RespondAsync(error); - return; - } - - } - } + if (Database.RemoveMessage(identifier)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Message removed." + }, true); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Failed removing the message from the database." + }, true); + } + } } \ No newline at end of file diff --git a/SupportChild/Commands/RemoveStaffCommand.cs b/SupportChild/Commands/RemoveStaffCommand.cs index a48f96f..70e2162 100644 --- a/SupportChild/Commands/RemoveStaffCommand.cs +++ b/SupportChild/Commands/RemoveStaffCommand.cs @@ -1,104 +1,49 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; +using System.Threading.Tasks; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; using MySql.Data.MySqlClient; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class RemoveStaffCommand : ApplicationCommandModule { - public class RemoveStaffCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("removestaff", "Removes a staff member.")] + public async Task OnExecute(InteractionContext command, [Option("User", "User to remove from staff.")] DiscordUser user) { - [Command("removestaff")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + if (!Database.IsStaff(user.Id)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "removestaff")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the removestaff command but did not have permission."); - return; - } + Color = DiscordColor.Red, + Description = "User is already not registered as staff." + }, true); + return; + } - ulong userID; - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); + await using MySqlConnection c = Database.GetConnection(); + c.Open(); + MySqlCommand deletion = new MySqlCommand(@"DELETE FROM staff WHERE user_id=@user_id", c); + deletion.Parameters.AddWithValue("@user_id", user.Id); + deletion.Prepare(); + deletion.ExecuteNonQuery(); - if (!parsedMessage.Any()) + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "User was removed from staff." + }, true); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { - userID = command.Member.Id; - } - else if (!ulong.TryParse(parsedMessage[0], out userID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } - - try - { - await command.Client.GetUserAsync(userID); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not find user on Discord)" - }; - await command.RespondAsync(error); - return; - } - - if (!Database.IsStaff(userID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "User is already not registered as staff." - }; - await command.RespondAsync(error); - return; - } - - using (MySqlConnection c = Database.GetConnection()) - { - c.Open(); - MySqlCommand deletion = new MySqlCommand(@"DELETE FROM staff WHERE user_id=@user_id", c); - deletion.Parameters.AddWithValue("@user_id", userID); - deletion.Prepare(); - deletion.ExecuteNonQuery(); - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "User was removed from staff." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "User was removed from staff.\n", - }; - await logChannel.SendMessageAsync(logMessage); - } - } + Color = DiscordColor.Green, + Description = "User was removed from staff.\n" + }); } } } \ No newline at end of file diff --git a/SupportChild/Commands/SayCommand.cs b/SupportChild/Commands/SayCommand.cs index 5eaedd1..b198b9c 100644 --- a/SupportChild/Commands/SayCommand.cs +++ b/SupportChild/Commands/SayCommand.cs @@ -1,78 +1,29 @@ -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.Entities; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class SayCommand : ApplicationCommandModule { - public class SayCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("say", "Prints a message with information from staff. Use without identifier to list all identifiers.")] + public async Task OnExecute(InteractionContext command, [Option("Identifier", "(Optional) The identifier word to summon a message.")] string identifier = null) { - [Command("say")] - [Cooldown(1, 2, CooldownBucketType.Channel)] - [Description("Prints a message with information from staff.")] - public async Task OnExecute(CommandContext command, string identifier) + // Print list of all messages if no identifier is provided + if (identifier == null) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "say")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission."); - return; - } - - if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message message)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "There is no message with that identifier." - }; - await command.RespondAsync(error); - return; - } - - DiscordEmbed reply = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = message.message - }; - await command.RespondAsync(reply); - } - - [Command("say")] - [Cooldown(1, 2.0, CooldownBucketType.Channel)] - [Description("Prints a list of staff messages.")] - public async Task OnExecute(CommandContext command) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "say")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission."); - return; - } - - List messages = Database.GetAllMessages(); if (!messages.Any()) { - DiscordEmbed error = new DiscordEmbedBuilder() - .WithColor(DiscordColor.Red) - .WithDescription("There are no messages registered."); - await command.RespondAsync(error); + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There are no messages registered." + }, true); return; } @@ -85,12 +36,32 @@ namespace SupportChild.Commands LinkedList listMessages = Utilities.ParseListIntoMessages(listItems); foreach (string listMessage in listMessages) { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Available messages: ") - .WithColor(DiscordColor.Green) - .WithDescription(listMessage); - await command.RespondAsync(channelInfo); + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Title = "Available messages: ", + Color = DiscordColor.Green, + Description = listMessage + }, true); } } + // Print specific message + else + { + if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message message)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "There is no message with that identifier." + }, true); + return; + } + + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Cyan, + Description = message.message.Replace("\\n", "\n") + }); + } } } \ No newline at end of file diff --git a/SupportChild/Commands/SetSummaryCommand.cs b/SupportChild/Commands/SetSummaryCommand.cs index 81b0ca5..6d9e87e 100644 --- a/SupportChild/Commands/SetSummaryCommand.cs +++ b/SupportChild/Commands/SetSummaryCommand.cs @@ -1,63 +1,42 @@ using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; using MySql.Data.MySqlClient; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class SetSummaryCommand : ApplicationCommandModule { - public class SetSummaryCommand : BaseCommandModule - { - [Command("setsummary")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "setsummary")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the setsummary command but did not have permission."); - return; - } + [SlashRequireGuild] + [SlashCommand("setsummary", "Sets a ticket's summary for the summary command.")] + public async Task OnExecute(InteractionContext command, [Option("Summary", "The ticket summary text.")] string summary) + { + ulong channelID = command.Channel.Id; + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket _)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }); + return; + } - ulong channelID = command.Channel.Id; - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } + await using MySqlConnection c = Database.GetConnection(); + c.Open(); + MySqlCommand update = new MySqlCommand(@"UPDATE tickets SET summary = @summary WHERE channel_id = @channel_id", c); + update.Parameters.AddWithValue("@summary", summary); + update.Parameters.AddWithValue("@channel_id", channelID); + update.Prepare(); + update.ExecuteNonQuery(); + update.Dispose(); - string summary = command.Message.Content.Replace(Config.prefix + "setsummary", "").Trim(); - - using (MySqlConnection c = Database.GetConnection()) - { - c.Open(); - MySqlCommand update = new MySqlCommand(@"UPDATE tickets SET summary = @summary WHERE channel_id = @channel_id", c); - update.Parameters.AddWithValue("@summary", summary); - update.Parameters.AddWithValue("@channel_id", channelID); - update.Prepare(); - update.ExecuteNonQuery(); - update.Dispose(); - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Summary set." - }; - await command.RespondAsync(message); - } - } - } + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Summary set." + }, true); + } } \ No newline at end of file diff --git a/SupportChild/Commands/SetTicketCommand.cs b/SupportChild/Commands/SetTicketCommand.cs deleted file mode 100644 index 11797ec..0000000 --- a/SupportChild/Commands/SetTicketCommand.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; -using MySql.Data.MySqlClient; - -namespace SupportChild.Commands -{ - public class SetTicketCommand :BaseCommandModule - { - [Command("setticket")] - [Description("Turns a channel into a ticket, warning: this will let anyone with write access delete the channel using the close command.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - using (MySqlConnection c = Database.GetConnection()) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "setticket")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the setticket command but did not have permission."); - return; - } - - // Check if ticket exists in the database - if (Database.IsOpenTicket(command.Channel.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is already a ticket." - }; - await command.RespondAsync(error); - return; - } - - ulong userID; - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); - - if (!parsedMessage.Any()) - { - userID = command.Member.Id; - } - else if (!ulong.TryParse(parsedMessage[0], out userID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } - - DiscordUser user = await command.Client.GetUserAsync(userID); - - if (user == null) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention." - }; - await command.RespondAsync(error); - return; - } - - long id = Database.NewTicket(userID, 0, command.Channel.Id); - string ticketID = id.ToString("00000"); - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Channel has been designated ticket " + ticketID + "." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = command.Channel.Mention + " has been designated ticket " + ticketID + " by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - } - } -} \ No newline at end of file diff --git a/SupportChild/Commands/StatusCommand.cs b/SupportChild/Commands/StatusCommand.cs index 8521b80..dec688b 100644 --- a/SupportChild/Commands/StatusCommand.cs +++ b/SupportChild/Commands/StatusCommand.cs @@ -1,41 +1,26 @@ using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class StatusCommand : ApplicationCommandModule { - public class StatusCommand : BaseCommandModule - { - [Command("status")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "status")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the status command but did not have permission."); - return; - } + [SlashRequireGuild] + [SlashCommand("status", "Shows bot status and information.")] + public async Task OnExecute(InteractionContext command) + { + long openTickets = Database.GetNumberOfTickets(); + long closedTickets = Database.GetNumberOfClosedTickets(); - long openTickets = Database.GetNumberOfTickets(); - long closedTickets = Database.GetNumberOfClosedTickets(); - - DiscordEmbed botInfo = new DiscordEmbedBuilder() - .WithAuthor("EmotionChild/SupportChild @ GitHub", "https://github.com/EmotionChild/SupportChild", "https://cdn.emotionchild.com/Ellie.png") - .WithTitle("Bot information") - .WithColor(DiscordColor.Cyan) - .AddField("Version:", SupportChild.GetVersion(), false) - .AddField("Open tickets:", openTickets + "", true) - .AddField("Closed tickets (1.1.0+ tickets only):", closedTickets + " ", true); - await command.RespondAsync(botInfo); - } - } + DiscordEmbed botInfo = new DiscordEmbedBuilder() + .WithAuthor("KarlofDuty/SupportBoi @ GitHub", "https://github.com/EmotionChild/SupportChild", "https://cdn.discordapp.com/attachments/765441543100170271/914327948667011132/Ellie_Concept_2_transparent_ver.png") + .WithTitle("Bot information") + .WithColor(DiscordColor.Cyan) + .AddField("Version:", SupportChild.GetVersion()) + .AddField("Open tickets:", openTickets + "", true) + .AddField("Closed tickets:", closedTickets + " ", true); + await command.CreateResponseAsync(botInfo); + } } \ No newline at end of file diff --git a/SupportChild/Commands/SummaryCommand.cs b/SupportChild/Commands/SummaryCommand.cs index 360db00..69a0a3b 100644 --- a/SupportChild/Commands/SummaryCommand.cs +++ b/SupportChild/Commands/SummaryCommand.cs @@ -1,51 +1,35 @@ using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class SummaryCommand : ApplicationCommandModule { - public class SummaryCommand : BaseCommandModule - { - [Command("summary")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "summary")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the summary command but did not have permission."); - return; - } - - if (Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - DiscordEmbed channelInfo = new DiscordEmbedBuilder() - .WithTitle("Channel information") - .WithColor(DiscordColor.Cyan) - .AddField("Ticket number:", ticket.id.ToString(), true) - .AddField("Ticket creator:", $"<@{ticket.creatorID}>", true) - .AddField("Assigned staff:", ticket.assignedStaffID == 0 ? "Unassigned." : $"<@{ticket.assignedStaffID}>", true) - .AddField("Creation time:", ticket.createdTime.ToString(Config.timestampFormat), true) - .AddField("Summary:", string.IsNullOrEmpty(ticket.summary) ? "No summary." : ticket.summary, false); - await command.RespondAsync(channelInfo); - } - else - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - } - } - } + [SlashRequireGuild] + [SlashCommand("summary", "Lists tickets assigned to a user.")] + public async Task OnExecute(InteractionContext command) + { + if (Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + { + DiscordEmbed channelInfo = new DiscordEmbedBuilder() + .WithTitle("Channel information") + .WithColor(DiscordColor.Cyan) + .AddField("Ticket number:", ticket.id.ToString("00000"), true) + .AddField("Ticket creator:", $"<@{ticket.creatorID}>", true) + .AddField("Assigned staff:", ticket.assignedStaffID == 0 ? "Unassigned." : $"<@{ticket.assignedStaffID}>", true) + .AddField("Creation time:", ticket.DiscordRelativeTime(), true) + .AddField("Summary:", string.IsNullOrEmpty(ticket.summary) ? "No summary." : ticket.summary.Replace("\\n", "\n")); + await command.CreateResponseAsync(channelInfo); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + } + } } \ No newline at end of file diff --git a/SupportChild/Commands/ToggleActiveCommand.cs b/SupportChild/Commands/ToggleActiveCommand.cs index b953367..1e07cfa 100644 --- a/SupportChild/Commands/ToggleActiveCommand.cs +++ b/SupportChild/Commands/ToggleActiveCommand.cs @@ -1,78 +1,44 @@ -using System.Linq; -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; +using System.Threading.Tasks; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; -using MySql.Data.MySqlClient; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class ToggleActiveCommand : ApplicationCommandModule { - public class ToggleActiveCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("toggleactive", "Toggles active status for a staff member.")] + public async Task OnExecute(InteractionContext command, [Option("User", "(Optional) Staff member to toggle activity for.")] DiscordUser user = null) { - [Command("toggleactive")] - [Aliases("ta")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + DiscordUser staffUser = user == null ? command.User : user; + + // Check if ticket exists in the database + if (!Database.TryGetStaff(staffUser.Id, out Database.StaffMember staffMember)) { - using (MySqlConnection c = Database.GetConnection()) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "toggleactive")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the toggleactive command but did not have permission."); - return; - } + Color = DiscordColor.Red, + Description = user == null ? "You have not been registered as staff." : "The user is not registered as staff." + }, true); + return; + } - ulong staffID; - string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); - - if (!parsedMessage.Any()) - { - staffID = command.Member.Id; - } - else if (!ulong.TryParse(parsedMessage[0], out staffID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Invalid ID/Mention. (Could not convert to numerical)" - }; - await command.RespondAsync(error); - return; - } - - // Check if ticket exists in the database - if (!Database.TryGetStaff(staffID, out Database.StaffMember staffMember)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You have not been registered as staff." - }; - await command.RespondAsync(error); - return; - } - - c.Open(); - MySqlCommand update = new MySqlCommand(@"UPDATE staff SET active = @active WHERE user_id = @user_id", c); - update.Parameters.AddWithValue("@user_id", staffID); - update.Parameters.AddWithValue("@active", !staffMember.active); - update.Prepare(); - update.ExecuteNonQuery(); - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = staffMember.active ? "Staff member is now set as inactive and will no longer be randomly assigned any support tickets." : "Staff member is now set as active and will be randomly assigned support tickets again." - }; - await command.RespondAsync(message); - } + if (Database.SetStaffActive(staffUser.Id, !staffMember.active)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = staffMember.active ? "Staff member is now set as inactive and will no longer be randomly assigned any support tickets." : "Staff member is now set as active and will be randomly assigned support tickets again." + }, true); + } + else + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error: Unable to update active status in database." + }, true); } } } \ No newline at end of file diff --git a/SupportChild/Commands/TranscriptCommand.cs b/SupportChild/Commands/TranscriptCommand.cs index 8fb24cd..0eb4bfc 100644 --- a/SupportChild/Commands/TranscriptCommand.cs +++ b/SupportChild/Commands/TranscriptCommand.cs @@ -2,171 +2,128 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class TranscriptCommand : ApplicationCommandModule { - public class TranscriptCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("transcript", "Creates a transcript of a ticket.")] + public async Task OnExecute(InteractionContext command, [Option("Ticket", "(Optional) Ticket number to get transcript of.")] long ticketID = 0) { - [Command("transcript")] - [Cooldown(1, 5, CooldownBucketType.User)] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + await command.DeferAsync(true); + Database.Ticket ticket; + if (ticketID == 0) // If there are no arguments use current channel { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "transcript")) + if (Database.TryGetOpenTicket(command.Channel.Id, out ticket)) { - DiscordEmbed error = new DiscordEmbedBuilder + try + { + await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); + } + catch (Exception) + { + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "ERROR: Could not save transcript file. Aborting..." + })); + throw; + } + } + else + { + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the transcript command but did not have permission."); + Description = "This channel is not a ticket." + })); return; } - - Database.Ticket ticket; - string strippedMessage = command.Message.Content.Replace(Config.prefix, ""); - string[] parsedMessage = strippedMessage.Replace("<@!", "").Replace("<@", "").Replace(">", "").Split(); - - // If there are no arguments use current channel - if (parsedMessage.Length < 2) + } + else + { + // If the ticket is still open, generate a new fresh transcript + if (Database.TryGetOpenTicketByID((uint)ticketID, out ticket) && ticket?.creatorID == command.Member.Id) { - if (Database.TryGetOpenTicket(command.Channel.Id, out ticket)) + try { - try - { - await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "ERROR: Could not save transcript file. Aborting..." - }; - await command.RespondAsync(error); - throw; - } + await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); } - else + catch (Exception) { - DiscordEmbed error = new DiscordEmbedBuilder + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; + Description = "ERROR: Could not save transcript file. Aborting..." + })); + throw; } + } - else + // If there is no open or closed ticket, send an error. If there is a closed ticket we will simply use the old transcript from when the ticket was closed. + else if (!Database.TryGetClosedTicket((uint)ticketID, out ticket) || (ticket?.creatorID != command.Member.Id && !Database.IsStaff(command.Member.Id))) { - // Check if argument is numerical, if not abort - if (!uint.TryParse(parsedMessage[1], out uint ticketID)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Argument must be a number." - }; - await command.RespondAsync(error); - return; - } - - // If the ticket is still open, generate a new fresh transcript - if (Database.TryGetOpenTicketByID(ticketID, out ticket) && ticket?.creatorID == command.Member.Id) - { - try - { - await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); - } - catch (Exception) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "ERROR: Could not save transcript file. Aborting..." - }; - await command.RespondAsync(error); - throw; - } - - } - // If there is no open or closed ticket, send an error. If there is a closed ticket we will simply use the old transcript from when the ticket was closed. - else if (!Database.TryGetClosedTicket(ticketID, out ticket) || (ticket?.creatorID != command.Member.Id && !Database.IsStaff(command.Member.Id))) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Could not find a closed ticket with that number which you opened." + (Config.HasPermission(command.Member, "list") ? "\n(Use the " + Config.prefix + "list command to see all your tickets)" : "") - }; - await command.RespondAsync(error); - return; - } - } - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed embed = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Ticket " + ticket.id.ToString("00000") + " transcript generated by " + command.Member.Mention + ".\n", - Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + command.Channel.Name } - }; - - using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) - { - DiscordMessageBuilder message = new DiscordMessageBuilder(); - message.WithEmbed(embed); - message.WithFiles(new Dictionary() { { Transcriber.GetFilename(ticket.id), file } }); - - await logChannel.SendMessageAsync(message); - } - } - - try - { - // Send transcript privately - DiscordEmbed directMessageEmbed = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Transcript generated, " + command.Member.Mention + "!\n" - }; - - using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) - { - DiscordMessageBuilder directMessage = new DiscordMessageBuilder(); - directMessage.WithEmbed(directMessageEmbed); - directMessage.WithFiles(new Dictionary() { { Transcriber.GetFilename(ticket.id), file } }); - - await command.Member.SendMessageAsync(directMessage); - } - - // Respond to message directly - DiscordEmbed response = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Transcript sent, " + command.Member.Mention + "!\n" - }; - await command.RespondAsync(response); - } - catch (UnauthorizedException) - { - // Send transcript privately - DiscordEmbed error = new DiscordEmbedBuilder + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "Not allowed to send direct message to you, " + command.Member.Mention + ", please check your privacy settings.\n" - }; - await command.RespondAsync(error); + Description = "Could not find a closed ticket with that number which you opened.\n(Use the /list command to see all your tickets)" + })); + return; } } + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read); + + DiscordMessageBuilder message = new DiscordMessageBuilder(); + message.WithEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Ticket " + ticket.id.ToString("00000") + " transcript generated by " + command.Member.Mention + ".\n", + Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + command.Channel.Name } + }); + message.WithFiles(new Dictionary { { Transcriber.GetFilename(ticket.id), file } }); + + await logChannel.SendMessageAsync(message); + } + + try + { + // Send transcript in a direct message + await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read); + + DiscordMessageBuilder directMessage = new DiscordMessageBuilder(); + directMessage.WithEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Transcript generated!\n" + }); + directMessage.WithFiles(new Dictionary { { Transcriber.GetFilename(ticket.id), file } }); + + await command.Member.SendMessageAsync(directMessage); + } + catch (UnauthorizedException) + { + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Not allowed to send direct message to you, please check your privacy settings.\n" + })); + return; + } + + await command.EditResponseAsync(new DiscordWebhookBuilder().AddEmbed(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Transcript sent!\n" + })); } } \ No newline at end of file diff --git a/SupportChild/Commands/UnassignComand.cs b/SupportChild/Commands/UnassignComand.cs index 5b892a8..42e272c 100644 --- a/SupportChild/Commands/UnassignComand.cs +++ b/SupportChild/Commands/UnassignComand.cs @@ -1,71 +1,52 @@ using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class UnassignCommand : ApplicationCommandModule { - public class UnassignCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("unassign", "Unassigns a staff member from a ticket.")] + public async Task OnExecute(InteractionContext command) { - [Command("unassign")] - [Description("Unassigns a staff member from a ticket.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + // Check if ticket exists in the database + if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "unassign")) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the unassign command but did not have permission."); - return; - } + Color = DiscordColor.Red, + Description = "This channel is not a ticket." + }, true); + return; + } - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) + if (!Database.UnassignStaff(ticket)) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } + Color = DiscordColor.Red, + Description = "Error: Failed to unassign staff member from ticket." + }, true); + return; + } - if (!Database.UnassignStaff(ticket)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Failed to unassign staff from ticket." - }; - await command.RespondAsync(error); - return; - } + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Green, + Description = "Unassigned staff member from ticket." + }); - DiscordEmbed message = new DiscordEmbedBuilder + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { Color = DiscordColor.Green, - Description = "Unassigned staff from ticket." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Staff was unassigned from " + command.Channel.Mention + " by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } + Description = "Staff member was unassigned from " + command.Channel.Mention + " by " + command.Member.Mention + "." + }); } } } \ No newline at end of file diff --git a/SupportChild/Commands/UnblacklistCommand.cs b/SupportChild/Commands/UnblacklistCommand.cs index e73e5b3..30d591a 100644 --- a/SupportChild/Commands/UnblacklistCommand.cs +++ b/SupportChild/Commands/UnblacklistCommand.cs @@ -1,99 +1,54 @@ using System; using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; using DSharpPlus.Entities; -using DSharpPlus.Exceptions; -using Microsoft.Extensions.Logging; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; -namespace SupportChild.Commands +namespace SupportChild.Commands; + +public class UnblacklistCommand : ApplicationCommandModule { - public class UnblacklistCommand : BaseCommandModule + [SlashRequireGuild] + [SlashCommand("unblacklist", "Unblacklists a user from opening tickets.")] + public async Task OnExecute(InteractionContext command, [Option("User", "User to remove from blacklist.")] DiscordUser user) { - [Command("unblacklist")] - [Description("Un-blacklists a user from opening tickets.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) + try { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "unblacklist")) + if (!Database.Unblacklist(user.Id)) { - DiscordEmbed error = new DiscordEmbedBuilder + await command.CreateResponseAsync(new DiscordEmbedBuilder { Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the unblacklist command but did not have permission."); + Description = user.Mention + " is not blacklisted." + }, true); return; } - string[] words = Utilities.ParseIDs(command.RawArgumentString); - foreach (string word in words) + await command.CreateResponseAsync(new DiscordEmbedBuilder { - if (ulong.TryParse(word, out ulong userId)) + Color = DiscordColor.Green, + Description = "Removed " + user.Mention + " from blacklist." + }, true); + + // Log it if the log channel exists + DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); + if (logChannel != null) + { + await logChannel.SendMessageAsync(new DiscordEmbedBuilder { - DiscordUser blacklistedUser = null; - try - { - blacklistedUser = await command.Client.GetUserAsync(userId); - } - catch (NotFoundException) { } - - if (blacklistedUser == null) - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error: Could not find user." - }; - await command.RespondAsync(message); - continue; - } - - try - { - if (!Database.Unblacklist(blacklistedUser.Id)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = blacklistedUser.Mention + " is not blacklisted." - }; - await command.RespondAsync(error); - continue; - } - - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Removed " + blacklistedUser.Mention + " from blacklist." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = blacklistedUser.Mention + " was unblacklisted from opening tickets by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - catch (Exception) - { - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "Error occured while removing " + blacklistedUser.Mention + " from blacklist." - }; - await command.RespondAsync(message); - throw; - } - } + Color = DiscordColor.Green, + Description = user.Mention + " was unblacklisted from opening tickets by " + command.Member.Mention + "." + }); } } + catch (Exception) + { + await command.CreateResponseAsync(new DiscordEmbedBuilder + { + Color = DiscordColor.Red, + Description = "Error occured while removing " + user.Mention + " from blacklist." + }, true); + throw; + } } } \ No newline at end of file diff --git a/SupportChild/Commands/UnsetTicketCommand.cs b/SupportChild/Commands/UnsetTicketCommand.cs deleted file mode 100644 index 1ead160..0000000 --- a/SupportChild/Commands/UnsetTicketCommand.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Threading.Tasks; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using Microsoft.Extensions.Logging; -using MySql.Data.MySqlClient; - -namespace SupportChild.Commands -{ - public class UnsetTicketCommand : BaseCommandModule - { - [Command("unsetticket")] - [Description( - "Deletes a channel from the ticket system without deleting the channel.")] - public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) - { - using (MySqlConnection c = Database.GetConnection()) - { - // Check if the user has permission to use this command. - if (!Config.HasPermission(command.Member, "unsetticket")) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "You do not have permission to use this command." - }; - await command.RespondAsync(error); - command.Client.Logger.Log(LogLevel.Information, "User tried to use the unsetticket command but did not have permission."); - return; - } - - // Check if ticket exists in the database - if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) - { - DiscordEmbed error = new DiscordEmbedBuilder - { - Color = DiscordColor.Red, - Description = "This channel is not a ticket." - }; - await command.RespondAsync(error); - return; - } - - c.Open(); - MySqlCommand deletion = new MySqlCommand(@"DELETE FROM tickets WHERE channel_id=@channel_id", c); - deletion.Parameters.AddWithValue("@channel_id", command.Channel.Id); - deletion.Prepare(); - deletion.ExecuteNonQuery(); - DiscordEmbed message = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = "Channel has been undesignated as a ticket." - }; - await command.RespondAsync(message); - - // Log it if the log channel exists - DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); - if (logChannel != null) - { - DiscordEmbed logMessage = new DiscordEmbedBuilder - { - Color = DiscordColor.Green, - Description = command.Channel.Mention + " has been undesignated as a ticket by " + command.Member.Mention + "." - }; - await logChannel.SendMessageAsync(logMessage); - } - } - } - } -} \ No newline at end of file