Updated to latest 5.0.0 nightly build of DSharpPlus

Still needs a new logger implementation and some new exception handling.
This commit is contained in:
Toastie 2024-12-26 18:36:20 +13:00
parent f89d50c982
commit 5c75e1fa7d
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4
33 changed files with 629 additions and 531 deletions

View file

@ -1,19 +1,24 @@
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class AddCategoryCommand : ApplicationCommandModule
public class AddCategoryCommand
{
[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)
[RequireGuild]
[Command("addcategory")]
[Description("Adds a category to the ticket bot letting users open tickets in them.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("title")][Description("The name to display on buttons and in selection boxes.")] string title,
[Parameter("category")][Description("The category to add.")] DiscordChannel category)
{
if (!category.IsCategory)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "That channel is not a category."
@ -23,7 +28,7 @@ public class AddCategoryCommand : ApplicationCommandModule
if (string.IsNullOrWhiteSpace(title))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Invalid category title specified."
@ -33,7 +38,7 @@ public class AddCategoryCommand : ApplicationCommandModule
if (Database.TryGetCategory(category.Id, out Database.Category _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "That category is already registered."
@ -43,7 +48,7 @@ public class AddCategoryCommand : ApplicationCommandModule
if (Database.TryGetCategory(title, out Database.Category _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There is already a category with that title."
@ -53,7 +58,7 @@ public class AddCategoryCommand : ApplicationCommandModule
if (Database.AddCategory(title, category.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Category added."
@ -61,7 +66,7 @@ public class AddCategoryCommand : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed adding the category to the database."

View file

@ -1,22 +1,25 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class AddCommand : ApplicationCommandModule
public class AddCommand
{
[SlashRequireGuild]
[SlashCommand("add", "Adds a user to a ticket")]
public async Task OnExecute(InteractionContext command, [Option("User", "User to add to ticket.")] DiscordUser user)
[RequireGuild]
[Command("add")]
[Description("Adds a user to this ticket.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("User to add to ticket.")] DiscordUser user)
{
// Check if ticket exists in the database
if (!Database.IsOpenTicket(command.Channel.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -27,11 +30,12 @@ public class AddCommand : ApplicationCommandModule
DiscordMember member;
try
{
// TODO: This throws an exception instead of returning null now
member = (user == null ? command.Member : await command.Guild.GetMemberAsync(user.Id));
if (member == null)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -41,7 +45,7 @@ public class AddCommand : ApplicationCommandModule
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -51,28 +55,30 @@ public class AddCommand : ApplicationCommandModule
try
{
await command.Channel.AddOverwriteAsync(member, Permissions.AccessChannels);
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.Channel.AddOverwriteAsync(member, DiscordPermissions.AccessChannels);
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Added " + member.Mention + " to ticket."
});
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = member.Mention + " was added to " + command.Channel.Mention +
" by " + command.Member.Mention + "."
" by " + command.Member?.Mention + "."
});
}
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not add " + member.Mention + " to ticket, unknown error occured."

View file

@ -1,21 +1,24 @@
using DSharpPlus.Entities;
using System.ComponentModel;
using DSharpPlus.Entities;
using System.Threading.Tasks;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
namespace SupportChild.Commands;
public class AddMessageCommand : ApplicationCommandModule
public class AddMessageCommand
{
[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)
[RequireGuild]
[Command("addmessage")]
[Description("Adds a new message for the 'say' command.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("identifier")][Description("The identifier word used in the /say command.")] string identifier,
[Parameter("message")][Description("The message the /say command will return.")] string message)
{
if (string.IsNullOrEmpty(message))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "No message specified."
@ -25,7 +28,7 @@ public class AddMessageCommand : ApplicationCommandModule
if (Database.TryGetMessage(identifier.ToLower(), out Database.Message _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There is already a message with that identifier."
@ -35,7 +38,7 @@ public class AddMessageCommand : ApplicationCommandModule
if (Database.AddMessage(identifier, command.Member.Id, message))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Message added."
@ -43,7 +46,7 @@ public class AddMessageCommand : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed adding the message to the database."

View file

@ -1,17 +1,21 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using MySqlConnector;
namespace SupportChild.Commands;
public class AddStaffCommand : ApplicationCommandModule
public class AddStaffCommand
{
[SlashRequireGuild]
[SlashCommand("addstaff", "Adds a new staff member.")]
public async Task OnExecute(InteractionContext command, [Option("User", "User to add to staff.")] DiscordUser user)
[RequireGuild]
[Command("addstaff")]
[Description("Adds a new staff member.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("User to add to staff.")] DiscordUser user)
{
DiscordMember staffMember = null;
try
@ -20,7 +24,7 @@ public class AddStaffCommand : ApplicationCommandModule
if (staffMember == null)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -30,7 +34,7 @@ public class AddStaffCommand : ApplicationCommandModule
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -47,14 +51,16 @@ public class AddStaffCommand : ApplicationCommandModule
cmd.ExecuteNonQuery();
cmd.Dispose();
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = staffMember.Mention + " was added to staff."
});
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder

View file

@ -1,25 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
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
[Command("admin")]
[Description("Administrative commands.")]
public class AdminCommands
{
[SlashRequireGuild]
[SlashCommand("listinvalid", "List tickets which channels have been deleted. Use /admin unsetticket <id> to remove them.")]
public async Task ListInvalid(InteractionContext command)
[RequireGuild]
[Command("listinvalid")]
[Description("List tickets which channels have been deleted. Use /admin unsetticket <id> to remove them.")]
public async Task ListInvalid(SlashCommandContext command)
{
if (!Database.TryGetOpenTickets(out List<Database.Ticket> openTickets))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not get any open tickets from database."
@ -28,7 +32,7 @@ public class AdminCommands : ApplicationCommandModule
// Get all channels in all guilds the bot is part of
List<DiscordChannel> allChannels = new List<DiscordChannel>();
foreach (KeyValuePair<ulong, DiscordGuild> guild in SupportChild.discordClient.Guilds)
foreach (KeyValuePair<ulong, DiscordGuild> guild in SupportChild.client.Guilds)
{
try
{
@ -49,7 +53,7 @@ public class AdminCommands : ApplicationCommandModule
if (listItems.Count == 0)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "All tickets are valid!"
@ -86,14 +90,16 @@ public class AdminCommands : ApplicationCommandModule
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)
[RequireGuild]
[Command("setticket")]
[Description("Turns a channel into a ticket. WARNING: Anyone will be able to delete the channel using /close.")]
public async Task SetTicket(SlashCommandContext command,
[Parameter("user")][Description("(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
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is already a ticket."
@ -105,14 +111,16 @@ public class AdminCommands : ApplicationCommandModule
long id = Database.NewTicket(ticketUser.Id, 0, command.Channel.Id);
string ticketID = id.ToString("00000");
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Channel has been designated ticket " + ticketID + "."
});
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
@ -123,9 +131,11 @@ public class AdminCommands : ApplicationCommandModule
}
}
[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)
[RequireGuild]
[Command("unsetticket")]
[Description("Deletes a ticket from the ticket system without deleting the channel.")]
public async Task UnsetTicket(SlashCommandContext command,
[Parameter("ticket-id")][Description("(Optional) Ticket to unset. Uses the channel you are in by default.")] long ticketID = 0)
{
Database.Ticket ticket;
@ -134,7 +144,7 @@ public class AdminCommands : ApplicationCommandModule
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket!"
@ -147,7 +157,7 @@ public class AdminCommands : ApplicationCommandModule
// Check if ticket exists in the database
if (!Database.TryGetOpenTicketByID((uint)ticketID, out ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There is no ticket with this ticket ID."
@ -159,14 +169,16 @@ public class AdminCommands : ApplicationCommandModule
if (Database.DeleteOpenTicket(ticket.id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Channel has been undesignated as a ticket."
});
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
@ -178,7 +190,7 @@ public class AdminCommands : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed removing ticket from database."
@ -186,10 +198,11 @@ public class AdminCommands : ApplicationCommandModule
}
}
[SlashCommand("reload", "Reloads the bot config.")]
public async Task Reload(InteractionContext command)
[Command("reload")]
[Description("Reloads the bot config.")]
public async Task Reload(SlashCommandContext command)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Reloading bot application..."

View file

@ -1,17 +1,21 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class AssignCommand : ApplicationCommandModule
public class AssignCommand
{
[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)
[RequireGuild]
[Command("assign")]
[Description("Assigns a staff member to this ticket.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("(Optional) User to assign to this ticket.")] DiscordUser user = null)
{
DiscordMember member = null;
try
@ -20,7 +24,7 @@ public class AssignCommand : ApplicationCommandModule
if (member == null)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -30,7 +34,7 @@ public class AssignCommand : ApplicationCommandModule
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not find that user in this server."
@ -41,7 +45,7 @@ public class AssignCommand : ApplicationCommandModule
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -51,7 +55,7 @@ public class AssignCommand : ApplicationCommandModule
if (!Database.IsStaff(member.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: User is not registered as staff."
@ -61,7 +65,7 @@ public class AssignCommand : ApplicationCommandModule
if (!Database.AssignStaff(ticket, member.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed to assign " + member.Mention + " to ticket."
@ -69,7 +73,7 @@ public class AssignCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Assigned " + member.Mention + " to ticket."
@ -88,8 +92,9 @@ public class AssignCommand : ApplicationCommandModule
catch (UnauthorizedException) { }
}
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder

View file

@ -1,22 +1,26 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class BlacklistCommand : ApplicationCommandModule
public class BlacklistCommand
{
[SlashRequireGuild]
[SlashCommand("blacklist", "Blacklists a user from opening tickets.")]
public async Task OnExecute(InteractionContext command, [Option("User", "User to blacklist.")] DiscordUser user)
[RequireGuild]
[Command("blacklist")]
[Description("Blacklists a user from opening tickets.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("User to blacklist.")] DiscordUser user)
{
try
{
if (!Database.Blacklist(user.Id, command.User.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = user.Mention + " is already blacklisted."
@ -24,14 +28,15 @@ public class BlacklistCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Blacklisted " + user.Mention + "."
}, true);
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
@ -43,7 +48,7 @@ public class BlacklistCommand : ApplicationCommandModule
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error occured while blacklisting " + user.Mention + "."

View file

@ -1,27 +1,30 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class CloseCommand : ApplicationCommandModule
public class CloseCommand
{
private static Dictionary<ulong, string> closeReasons = new Dictionary<ulong, string>();
[SlashRequireGuild]
[SlashCommand("close", "Closes a ticket.")]
public async Task OnExecute(InteractionContext command, [Option("Reason", "(Optional) Reason for closing the ticket.")] string reason = "")
[RequireGuild]
[Command("close")]
[Description("Closes this ticket.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("reason")][Description("(Optional) The reason for closing this ticket.")] string reason = "")
{
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -35,15 +38,15 @@ public class CloseCommand : ApplicationCommandModule
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, "supportchild_closeconfirm", "Confirm"));
.AddComponents(new DiscordButtonComponent(DiscordButtonStyle.Danger, "supportboi_closeconfirm", "Confirm"));
await command.CreateResponseAsync(confirmation);
await command.RespondAsync(confirmation);
closeReasons.Add(command.Channel.Id, reason);
}
public static async Task OnConfirmed(DiscordInteraction interaction)
{
await interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
await interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate);
ulong channelID = interaction.Channel.Id;
string channelName = interaction.Channel.Name;
@ -80,8 +83,10 @@ public class CloseCommand : ApplicationCommandModule
closeReason = "\nReason: " + cachedReason + "\n";
}
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = interaction.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await interaction.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed embed = new DiscordEmbedBuilder
@ -112,6 +117,7 @@ public class CloseCommand : ApplicationCommandModule
try
{
// TODO: This throws an exception instead of returning null now
DiscordMember staffMember = await interaction.Guild.GetMemberAsync(ticket.creatorID);
await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read);

View file

@ -1,28 +1,30 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class CreateButtonPanelCommand : ApplicationCommandModule
public class CreateButtonPanelCommand
{
[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)
[RequireGuild]
[Command("createbuttonpanel")]
[Description("Creates a series of buttons which users can use to open new tickets in specific categories.")]
public async Task OnExecute(SlashCommandContext command)
{
DiscordMessageBuilder builder = new DiscordMessageBuilder().WithContent(" ");
List<Database.Category> verifiedCategories = await Utilities.GetVerifiedChannels();
if (verifiedCategories.Count == 0)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: No registered categories found."
Description = "Error: No registered categories found. You have to use /addcategory first."
}, true);
return;
}
@ -36,13 +38,13 @@ public class CreateButtonPanelCommand : ApplicationCommandModule
for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < verifiedCategories.Count; nrOfButtons++)
{
buttonRow.Add(new DiscordButtonComponent(ButtonStyle.Primary, "supportchild_newticketbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name));
buttonRow.Add(new DiscordButtonComponent(DiscordButtonStyle.Primary, "supportchild_newticketbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name));
}
builder.AddComponents(buttonRow);
}
await command.Channel.SendMessageAsync(builder);
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Successfully created message, make sure to run this command again if you add new categories to the bot."
@ -51,7 +53,7 @@ public class CreateButtonPanelCommand : ApplicationCommandModule
public static async Task OnButtonUsed(DiscordInteraction interaction)
{
await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral());
await interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral());
if (!ulong.TryParse(interaction.Data.CustomId.Replace("supportchild_newticketbutton ", ""), out ulong categoryID) || categoryID == 0)
{

View file

@ -1,32 +1,35 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class CreateSelectionBoxPanelCommand : ApplicationCommandModule
public class CreateSelectionBoxPanelCommand
{
[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)
[RequireGuild]
[Command("createselectionboxpanel")]
[Description("Creates a selection box which users can use to open new tickets in specific categories.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("message")][Description("(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
await command.RespondAsync(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<List<DiscordSelectComponent>> GetSelectComponents(InteractionContext command, string placeholder)
public static async Task<List<DiscordSelectComponent>> GetSelectComponents(SlashCommandContext command, string placeholder)
{
List<Database.Category> verifiedCategories = await Utilities.GetVerifiedChannels();
@ -65,7 +68,7 @@ public class CreateSelectionBoxPanelCommand : ApplicationCommandModule
return;
}
await interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral());
await interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder().AsEphemeral());
(bool success, string message) = await NewCommand.OpenNewTicket(interaction.User.Id, interaction.ChannelId, categoryID);

View file

@ -1,24 +1,28 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class ListAssignedCommand : ApplicationCommandModule
public class ListAssignedCommand
{
[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)
[RequireGuild]
[Command("listassigned")]
[Description("Lists tickets assigned to a user.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("(Optional) User to list tickets for.")] DiscordUser user = null)
{
DiscordUser listUser = user == null ? command.User : user;
if (!Database.TryGetAssignedTickets(listUser.Id, out List<Database.Ticket> assignedTickets))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "User does not have any assigned tickets."

View file

@ -1,18 +1,22 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class ListCommand : ApplicationCommandModule
public class ListCommand
{
[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)
[RequireGuild]
[Command("list")]
[Description("Lists tickets opened by a user.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("(Optional) The user to get tickets by.")] DiscordUser user = null)
{
DiscordUser listUser = user == null ? command.User : user;
@ -80,7 +84,7 @@ public class ListCommand : ApplicationCommandModule
if (embeds.Count == 0)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Cyan,
Description = "User does not have any open or closed tickets."

View file

@ -1,22 +1,25 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class ListOpen : ApplicationCommandModule
public class ListOpen
{
[SlashRequireGuild]
[SlashCommand("listopen", "Lists all open tickets, oldest first.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("listopen")]
[Description("Lists all open tickets, oldest first.")]
public async Task OnExecute(SlashCommandContext command)
{
if (!Database.TryGetOpenTickets(out List<Database.Ticket> openTickets))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not fetch any open tickets."

View file

@ -1,22 +1,25 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class ListUnassignedCommand : ApplicationCommandModule
public class ListUnassignedCommand
{
[SlashRequireGuild]
[SlashCommand("listunassigned", "Lists unassigned tickets.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("listunassigned")]
[Description("Lists unassigned tickets.")]
public async Task OnExecute(SlashCommandContext command)
{
if (!Database.TryGetAssignedTickets(0, out List<Database.Ticket> unassignedTickets))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "There are no unassigned tickets."

View file

@ -1,24 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class MoveCommand : ApplicationCommandModule
public class MoveCommand
{
[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)
[RequireGuild]
[Command("move")]
[Description("Moves a ticket to another category.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("category")][Description("The category to move the ticket to. Only has to be the beginning of the name.")] string category)
{
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -28,7 +32,7 @@ public class MoveCommand : ApplicationCommandModule
if (string.IsNullOrEmpty(category))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: No category provided."
@ -42,7 +46,7 @@ public class MoveCommand : ApplicationCommandModule
if (categoryChannel == null)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Could not find a category by that name."
@ -52,7 +56,7 @@ public class MoveCommand : ApplicationCommandModule
if (command.Channel.Id == categoryChannel.Id)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: The ticket is already in that category."
@ -66,7 +70,7 @@ public class MoveCommand : ApplicationCommandModule
}
catch (UnauthorizedException)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Not authorized to move this ticket to that category."
@ -74,7 +78,7 @@ public class MoveCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Ticket was moved to " + categoryChannel.Mention

View file

@ -1,50 +1,52 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class NewCommand : ApplicationCommandModule
public class NewCommand
{
[SlashRequireGuild]
[SlashCommand("new", "Opens a new ticket.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("new")]
[Description("Opens a new ticket.")]
public async Task OnExecute(SlashCommandContext command)
{
List<Database.Category> verifiedCategories = await Utilities.GetVerifiedChannels();
switch (verifiedCategories.Count)
{
case 0:
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: No registered categories found."
}, true);
return;
case 1:
await command.DeferAsync(true);
await command.DeferResponseAsync(true);
(bool success, string message) = await OpenNewTicket(command.User.Id, command.Channel.Id, verifiedCategories[0].id);
if (success)
{
await command.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder
await command.FollowupAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = message
}).AsEphemeral());
}, true);
}
else
{
await command.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(new DiscordEmbedBuilder
await command.FollowupAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = message
}).AsEphemeral());
}, true);
}
return;
default:
@ -60,7 +62,7 @@ public class NewCommand : ApplicationCommandModule
}
}
public static async Task CreateButtons(InteractionContext command, List<Database.Category> verifiedCategories)
public static async Task CreateButtons(SlashCommandContext command, List<Database.Category> verifiedCategories)
{
DiscordInteractionResponseBuilder builder = new DiscordInteractionResponseBuilder().WithContent(" ");
@ -71,15 +73,15 @@ public class NewCommand : ApplicationCommandModule
for (; nrOfButtons < 5 * (nrOfButtonRows + 1) && nrOfButtons < verifiedCategories.Count; nrOfButtons++)
{
buttonRow.Add(new DiscordButtonComponent(ButtonStyle.Primary, "supportchild_newcommandbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name));
buttonRow.Add(new DiscordButtonComponent(DiscordButtonStyle.Primary, "supportchild_newcommandbutton " + verifiedCategories[nrOfButtons].id, verifiedCategories[nrOfButtons].name));
}
builder.AddComponents(buttonRow);
}
await command.CreateResponseAsync(builder.AsEphemeral());
await command.RespondAsync(builder.AsEphemeral());
}
public static async Task CreateSelector(InteractionContext command, List<Database.Category> verifiedCategories)
public static async Task CreateSelector(SlashCommandContext command, List<Database.Category> verifiedCategories)
{
verifiedCategories = verifiedCategories.OrderBy(x => x.name).ToList();
List<DiscordSelectComponent> selectionComponents = new List<DiscordSelectComponent>();
@ -96,7 +98,7 @@ public class NewCommand : ApplicationCommandModule
selectionComponents.Add(new DiscordSelectComponent("supportchild_newcommandselector" + selectionBoxes, "Open new ticket...", categoryOptions, false, 0, 1));
}
await command.CreateResponseAsync(new DiscordInteractionResponseBuilder().AddComponents(selectionComponents).AsEphemeral());
await command.RespondAsync(new DiscordInteractionResponseBuilder().AddComponents(selectionComponents).AsEphemeral());
}
public static async Task OnCategorySelection(DiscordInteraction interaction)
@ -104,10 +106,10 @@ public class NewCommand : ApplicationCommandModule
string stringID;
switch (interaction.Data.ComponentType)
{
case ComponentType.Button:
case DiscordComponentType.Button:
stringID = interaction.Data.CustomId.Replace("supportchild_newcommandbutton ", "");
break;
case ComponentType.StringSelect:
case DiscordComponentType.StringSelect:
if (interaction.Data.Values == null || interaction.Data.Values.Length <= 0)
{
return;
@ -115,8 +117,8 @@ public class NewCommand : ApplicationCommandModule
stringID = interaction.Data.Values[0];
break;
case ComponentType.ActionRow:
case ComponentType.FormInput:
case DiscordComponentType.ActionRow:
case DiscordComponentType.FormInput:
default:
return;
}
@ -126,7 +128,7 @@ public class NewCommand : ApplicationCommandModule
return;
}
await interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate, new DiscordInteractionResponseBuilder().AsEphemeral());
await interaction.CreateResponseAsync(DiscordInteractionResponseType.DeferredMessageUpdate, new DiscordInteractionResponseBuilder().AsEphemeral());
(bool success, string message) = await OpenNewTicket(interaction.User.Id, interaction.ChannelId, categoryID);
@ -161,9 +163,7 @@ public class NewCommand : ApplicationCommandModule
return (false, "You cannot use this command in a ticket channel.");
}
if (!Database.IsStaff(userID)
&& Database.TryGetOpenTickets(userID, out List<Database.Ticket> ownTickets)
&& (ownTickets.Count >= Config.ticketLimit && Config.ticketLimit != 0))
if (!Database.IsStaff(userID) && Database.TryGetOpenTickets(userID, out List<Database.Ticket> ownTickets) && ownTickets.Count >= Config.ticketLimit)
{
return (false, "You have reached the limit for maximum open tickets.");
}
@ -171,7 +171,7 @@ public class NewCommand : ApplicationCommandModule
DiscordChannel category = null;
try
{
category = await SupportChild.discordClient.GetChannelAsync(categoryID);
category = await SupportChild.client.GetChannelAsync(categoryID);
}
catch (Exception) { /*ignored*/ }
@ -196,7 +196,7 @@ public class NewCommand : ApplicationCommandModule
try
{
ticketChannel = await category.Guild.CreateChannelAsync("ticket", ChannelType.Text, category);
ticketChannel = await category.Guild.CreateChannelAsync("ticket", DiscordChannelType.Text, category);
}
catch (Exception) { /* ignored */ }
@ -227,7 +227,7 @@ public class NewCommand : ApplicationCommandModule
try
{
await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels);
await ticketChannel.AddOverwriteAsync(member, DiscordPermissions.AccessChannels);
}
catch (DiscordException e)
{
@ -238,12 +238,7 @@ public class NewCommand : ApplicationCommandModule
await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage);
// Refreshes the channel as changes were made to it above
ticketChannel = await SupportChild.discordClient.GetChannelAsync(ticketChannel.Id);
if (ticketChannel.Parent?.IsCategory ?? false)
{
Interviewer.StartInterview(ticketChannel);
}
ticketChannel = await SupportChild.client.GetChannelAsync(ticketChannel.Id);
if (staffID != 0)
{
@ -273,8 +268,10 @@ public class NewCommand : ApplicationCommandModule
}
}
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = category.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await category.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder

View file

@ -1,25 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using Microsoft.Extensions.Logging;
namespace SupportChild.Commands;
public class RandomAssignCommand : ApplicationCommandModule
public class RandomAssignCommand
{
[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)
[RequireGuild]
[Command("rassign")]
[Description("Randomly assigns a staff member to a ticket.")]
public async Task OnExecute(SlashCommandContext command, [Parameter("role")][Description("(Optional) Limit the random assignment to a specific role.")] DiscordRole role = null)
{
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: This channel is not a ticket."
@ -37,7 +40,7 @@ public class RandomAssignCommand : ApplicationCommandModule
// Attempt to assign the staff member to the ticket
if (!Database.AssignStaff(ticket, staffMember.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed to assign " + staffMember.Mention + " to ticket."
@ -46,7 +49,7 @@ public class RandomAssignCommand : ApplicationCommandModule
}
// Respond that the command was successful
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Randomly assigned " + staffMember.Mention + " to ticket."
@ -66,8 +69,9 @@ public class RandomAssignCommand : ApplicationCommandModule
catch (UnauthorizedException) { }
}
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
@ -78,7 +82,7 @@ public class RandomAssignCommand : ApplicationCommandModule
}
}
private static async Task<DiscordMember> GetRandomVerifiedStaffMember(InteractionContext command, DiscordRole targetRole, Database.Ticket ticket)
private static async Task<DiscordMember> GetRandomVerifiedStaffMember(SlashCommandContext command, DiscordRole targetRole, Database.Ticket ticket)
{
if (targetRole != null) // A role was provided
{
@ -112,7 +116,7 @@ public class RandomAssignCommand : ApplicationCommandModule
Database.StaffMember staffEntry = Database.GetRandomActiveStaff(ticket.assignedStaffID, ticket.creatorID);
if (staffEntry == null)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: There are no other staff members to choose from."
@ -129,7 +133,7 @@ public class RandomAssignCommand : ApplicationCommandModule
}
// Send a more generic error if we get to this point and still haven't found the staff member
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Could not find an applicable staff member."

View file

@ -1,19 +1,23 @@
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class RemoveCategoryCommand : ApplicationCommandModule
public class RemoveCategoryCommand
{
[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)
[RequireGuild]
[Command("removecategory")]
[Description("Removes the ability for users to open tickets in a specific category.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("category")][Description("The category to remove.")] DiscordChannel channel)
{
if (!Database.TryGetCategory(channel.Id, out Database.Category _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "That category is not registered."
@ -23,7 +27,7 @@ public class RemoveCategoryCommand : ApplicationCommandModule
if (Database.RemoveCategory(channel.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Category removed."
@ -31,7 +35,7 @@ public class RemoveCategoryCommand : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed removing the category from the database."

View file

@ -1,19 +1,23 @@
using DSharpPlus.Entities;
using System.ComponentModel;
using DSharpPlus.Entities;
using System.Threading.Tasks;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
namespace SupportChild.Commands;
public class RemoveMessageCommand : ApplicationCommandModule
public class RemoveMessageCommand
{
[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)
[RequireGuild]
[Command("removemessage")]
[Description("Removes a message from the 'say' command.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("identifier")][Description("The identifier word used in the /say command.")] string identifier)
{
if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message _))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There is no message with that identifier."
@ -23,7 +27,7 @@ public class RemoveMessageCommand : ApplicationCommandModule
if (Database.RemoveMessage(identifier))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Message removed."
@ -31,7 +35,7 @@ public class RemoveMessageCommand : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed removing the message from the database."

View file

@ -1,20 +1,24 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using MySqlConnector;
namespace SupportChild.Commands;
public class RemoveStaffCommand : ApplicationCommandModule
public class RemoveStaffCommand
{
[SlashRequireGuild]
[SlashCommand("removestaff", "Removes a staff member.")]
public async Task OnExecute(InteractionContext command, [Option("User", "User to remove from staff.")] DiscordUser user)
[RequireGuild]
[Command("removestaff")]
[Description("Removes a staff member.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("user")][Description("User to remove from staff.")] DiscordUser user)
{
if (!Database.IsStaff(user.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "User is already not registered as staff."
@ -26,17 +30,18 @@ public class RemoveStaffCommand : ApplicationCommandModule
c.Open();
MySqlCommand deletion = new MySqlCommand(@"DELETE FROM staff WHERE user_id=@user_id", c);
deletion.Parameters.AddWithValue("@user_id", user.Id);
deletion.Prepare();
await deletion.PrepareAsync();
deletion.ExecuteNonQuery();
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "User was removed from staff."
}, true);
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder

View file

@ -1,18 +1,22 @@
using DSharpPlus.Entities;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class SayCommand : ApplicationCommandModule
public class SayCommand
{
[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)
[RequireGuild]
[Command("say")]
[Description("Prints a message with information from staff. Use without identifier to list all identifiers.")]
public async Task OnExecute(SlashCommandContext command,
[Parameter("Identifier")][Description("(Optional) The identifier word to summon a message.")] string identifier = null)
{
// Print list of all messages if no identifier is provided
if (identifier == null)
@ -23,7 +27,7 @@ public class SayCommand : ApplicationCommandModule
if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message message))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There is no message with that identifier."
@ -31,19 +35,19 @@ public class SayCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Cyan,
Description = message.message.Replace("\\n", "\n")
});
}
private static async void SendMessageList(InteractionContext command)
private static async void SendMessageList(SlashCommandContext command)
{
List<Database.Message> messages = Database.GetAllMessages();
if (messages.Count == 0)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "There are no messages registered."

View file

@ -1,22 +1,25 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using MySqlConnector;
namespace SupportChild.Commands;
public class SetSummaryCommand : ApplicationCommandModule
public class SetSummaryCommand
{
[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)
[RequireGuild]
[Command("setsummary")]
[Description("Sets a ticket's summary for the summary command.")]
public async Task OnExecute(SlashCommandContext command, [Parameter("Summary")][Description("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
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -29,11 +32,11 @@ public class SetSummaryCommand : ApplicationCommandModule
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();
await update.PrepareAsync();
update.ExecuteNonQuery();
update.Dispose();
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Summary set."

View file

@ -1,15 +1,18 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class StatusCommand : ApplicationCommandModule
public class StatusCommand
{
[SlashRequireGuild]
[SlashCommand("status", "Shows bot status and information.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("status")]
[Description("Shows bot status and information.")]
public async Task OnExecute(SlashCommandContext command)
{
long openTickets = Database.GetNumberOfTickets();
long closedTickets = Database.GetNumberOfClosedTickets();
@ -23,6 +26,6 @@ public class StatusCommand : ApplicationCommandModule
.AddField("Closed tickets:", closedTickets + " ", true)
.AddField("Report bugs:", "[Toastielab Issues](https://toastielab.dev/Emotions-stuff/SupportChild/issues)", true)
.AddField("Commands:", "[Toastielab Repository](https://toastielab.dev/Emotions-stuff/SupportChild)", true);
await command.CreateResponseAsync(botInfo);
await command.RespondAsync(botInfo);
}
}
}

View file

@ -1,35 +1,37 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class SummaryCommand : ApplicationCommandModule
public class SummaryCommand
{
[SlashRequireGuild]
[SlashCommand("summary", "Lists tickets assigned to a user.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("summary")]
[Description("Lists tickets assigned to a user.")]
public async Task OnExecute(SlashCommandContext command)
{
if (Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
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
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
}, true);
return;
}
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.RespondAsync(channelInfo);
}
}

View file

@ -1,22 +1,25 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class ToggleActiveCommand : ApplicationCommandModule
public class ToggleActiveCommand
{
[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)
[RequireGuild]
[Command("toggleactive")]
[Description("Toggles active status for a staff member.")]
public async Task OnExecute(SlashCommandContext command, [Parameter("user")][Description("(Optional) Staff member to toggle activity for.")] DiscordUser user = null)
{
DiscordUser staffUser = user == null ? command.User : user;
// Check if ticket exists in the database
if (!Database.TryGetStaff(staffUser.Id, out Database.StaffMember staffMember))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = user == null ? "You have not been registered as staff." : "The user is not registered as staff."
@ -26,7 +29,7 @@ public class ToggleActiveCommand : ApplicationCommandModule
if (Database.SetStaffActive(staffUser.Id, !staffMember.active))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(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."
@ -34,7 +37,7 @@ public class ToggleActiveCommand : ApplicationCommandModule
}
else
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Unable to update active status in database."

View file

@ -1,21 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class TranscriptCommand : ApplicationCommandModule
public class TranscriptCommand
{
[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)
[RequireGuild]
[Command("transcript")]
[Description("Creates a transcript of a ticket.")]
public async Task OnExecute(SlashCommandContext command, [Parameter("ticket-id")][Description("(Optional) Ticket number to get transcript of.")] long ticketID = 0)
{
await command.DeferAsync(true);
await command.DeferResponseAsync(true);
Database.Ticket ticket;
if (ticketID == 0) // If there are no arguments use current channel
{
@ -76,9 +79,10 @@ public class TranscriptCommand : ApplicationCommandModule
return;
}
}
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read);

View file

@ -1,20 +1,23 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class UnassignCommand : ApplicationCommandModule
public class UnassignCommand
{
[SlashRequireGuild]
[SlashCommand("unassign", "Unassigns a staff member from a ticket.")]
public async Task OnExecute(InteractionContext command)
[RequireGuild]
[Command("unassign")]
[Description("Unassigns a staff member from a ticket.")]
public async Task OnExecute(SlashCommandContext command)
{
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
@ -24,7 +27,7 @@ public class UnassignCommand : ApplicationCommandModule
if (!Database.UnassignStaff(ticket))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed to unassign staff member from ticket."
@ -32,14 +35,15 @@ public class UnassignCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Unassigned staff member from ticket."
});
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder

View file

@ -1,22 +1,25 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
namespace SupportChild.Commands;
public class UnblacklistCommand : ApplicationCommandModule
public class UnblacklistCommand
{
[SlashRequireGuild]
[SlashCommand("unblacklist", "Unblacklists a user from opening tickets.")]
public async Task OnExecute(InteractionContext command, [Option("User", "User to remove from blacklist.")] DiscordUser user)
[RequireGuild]
[Command("unblacklist")]
[Description("Unblacklists a user from opening tickets.")]
public async Task OnExecute(SlashCommandContext command, [Parameter("user")][Description("User to remove from blacklist.")] DiscordUser user)
{
try
{
if (!Database.Unblacklist(user.Id))
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = user.Mention + " is not blacklisted."
@ -24,14 +27,15 @@ public class UnblacklistCommand : ApplicationCommandModule
return;
}
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Removed " + user.Mention + " from blacklist."
}, true);
// TODO: This throws an exception instead of returning null now
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
DiscordChannel logChannel = await command.Guild.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
await logChannel.SendMessageAsync(new DiscordEmbedBuilder
@ -43,7 +47,7 @@ public class UnblacklistCommand : ApplicationCommandModule
}
catch (Exception)
{
await command.CreateResponseAsync(new DiscordEmbedBuilder
await command.RespondAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error occured while removing " + user.Mention + " from blacklist."

View file

@ -2,35 +2,37 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DiscordChatExporter.Core.Utils.Extensions;
using DSharpPlus;
using DSharpPlus.Commands;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.EventArgs;
using DSharpPlus.Commands.Exceptions;
using DSharpPlus.Entities;
using DSharpPlus.EventArgs;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes;
using DSharpPlus.SlashCommands.EventArgs;
using SupportChild.Commands;
namespace SupportChild;
internal static class EventHandler
public static class EventHandler
{
internal static Task OnReady(DiscordClient client, ReadyEventArgs e)
public static Task OnReady(DiscordClient client, GuildDownloadCompletedEventArgs e)
{
Logger.Log("Client is ready to process events.");
Logger.Log("Connected to Discord.");
// Checking activity type
if (!Enum.TryParse(Config.presenceType, true, out ActivityType activityType))
if (!Enum.TryParse(Config.presenceType, true, out DiscordActivityType activityType))
{
Logger.Log("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead.");
activityType = ActivityType.Playing;
activityType = DiscordActivityType.Playing;
}
client.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online);
client.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), DiscordUserStatus.Online);
return Task.CompletedTask;
}
internal static async Task OnGuildAvailable(DiscordClient discordClient, GuildCreateEventArgs e)
public static async Task OnGuildAvailable(DiscordClient discordClient, GuildAvailableEventArgs e)
{
Logger.Log("Found Discord server: " + e.Guild.Name + " (" + e.Guild.Id + ")");
@ -49,21 +51,7 @@ internal static class EventHandler
}
}
internal static Task OnClientError(DiscordClient _, ClientErrorEventArgs e)
{
Logger.Error("Client exception occured:\n" + e.Exception);
switch (e.Exception)
{
case BadRequestException ex:
Logger.Error("JSON Message: " + ex.JsonMessage);
break;
default:
break;
}
return Task.CompletedTask;
}
internal static async Task OnMessageCreated(DiscordClient client, MessageCreateEventArgs e)
public static async Task OnMessageCreated(DiscordClient client, MessageCreatedEventArgs e)
{
if (e.Author.IsBot)
{
@ -76,15 +64,9 @@ internal static class EventHandler
return;
}
// Ignore staff messages
if (Database.IsStaff(e.Author.Id))
{
return;
}
// Sends a DM to the assigned staff member if at least a day has gone by since the last message
// Sends a DM to the assigned staff member if at least a day has gone by since the last message and the user sending the message isn't staff
IReadOnlyList<DiscordMessage> messages = await e.Channel.GetMessagesAsync(2);
if (messages.Count > 1 && messages[1].Timestamp < DateTimeOffset.UtcNow.AddDays(Config.ticketUpdatedNotificationDelay * -1))
if (messages.Count > 1 && messages[1].Timestamp < DateTimeOffset.UtcNow.AddDays(Config.ticketUpdatedNotificationDelay * -1) && !Database.IsStaff(e.Author.Id))
{
try
{
@ -100,42 +82,7 @@ internal static class EventHandler
}
}
internal static async Task OnCommandError(SlashCommandsExtension commandSystem, SlashCommandErrorEventArgs e)
{
switch (e.Exception)
{
case SlashExecutionChecksFailedException checksFailedException:
{
foreach (SlashCheckBaseAttribute attr in checksFailedException.FailedChecks)
{
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = ParseFailedCheck(attr)
});
}
return;
}
case BadRequestException ex:
Logger.Error("Command exception occured:\n" + e.Exception);
Logger.Error("JSON Message: " + ex.JsonMessage);
return;
default:
{
Logger.Error("Exception occured: " + e.Exception.GetType() + ": " + e.Exception);
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Internal error occured, please report this to the developer."
});
return;
}
}
}
internal static async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
public static async Task OnMemberAdded(DiscordClient client, GuildMemberAddedEventArgs e)
{
if (!Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
@ -151,7 +98,7 @@ internal static class EventHandler
{
try
{
await channel.AddOverwriteAsync(e.Member, Permissions.AccessChannels);
await channel.AddOverwriteAsync(e.Member, DiscordPermissions.AccessChannels);
await channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
@ -170,7 +117,7 @@ internal static class EventHandler
}
}
internal static async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e)
public static async Task OnMemberRemoved(DiscordClient client, GuildMemberRemovedEventArgs e)
{
if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
@ -217,22 +164,22 @@ internal static class EventHandler
}
}
internal static async Task OnComponentInteractionCreated(DiscordClient client, ComponentInteractionCreateEventArgs e)
public static async Task OnComponentInteractionCreated(DiscordClient client, ComponentInteractionCreatedEventArgs e)
{
try
{
switch (e.Interaction.Data.ComponentType)
{
case ComponentType.Button:
case DiscordComponentType.Button:
switch (e.Id)
{
case "supportchild_closeconfirm":
await CloseCommand.OnConfirmed(e.Interaction);
return;
case { } when e.Id.StartsWith("supportchild_newcommandbutton"):
case not null when e.Id.StartsWith("supportchild_newcommandbutton"):
await NewCommand.OnCategorySelection(e.Interaction);
return;
case { } when e.Id.StartsWith("supportchild_newticketbutton"):
case not null when e.Id.StartsWith("supportchild_newticketbutton"):
await CreateButtonPanelCommand.OnButtonUsed(e.Interaction);
return;
case "right":
@ -249,23 +196,23 @@ internal static class EventHandler
Logger.Warn("Unknown button press received! '" + e.Id + "'");
return;
}
case ComponentType.StringSelect:
case DiscordComponentType.StringSelect:
switch (e.Id)
{
case { } when e.Id.StartsWith("supportchild_newcommandselector"):
case not null when e.Id.StartsWith("supportchild_newcommandselector"):
await NewCommand.OnCategorySelection(e.Interaction);
return;
case { } when e.Id.StartsWith("supportchild_newticketselector"):
case not null when e.Id.StartsWith("supportchild_newticketselector"):
await CreateSelectionBoxPanelCommand.OnSelectionMenuUsed(e.Interaction);
return;
default:
Logger.Warn("Unknown selection box option received! '" + e.Id + "'");
return;
}
case ComponentType.ActionRow:
case DiscordComponentType.ActionRow:
Logger.Warn("Unknown action row received! '" + e.Id + "'");
return;
case ComponentType.FormInput:
case DiscordComponentType.FormInput:
Logger.Warn("Unknown form input received! '" + e.Id + "'");
return;
default:
@ -283,18 +230,38 @@ internal static class EventHandler
Logger.Error("Interaction Exception occured: " + ex.GetType() + ": " + ex);
}
}
private static string ParseFailedCheck(SlashCheckBaseAttribute attr)
public static async Task OnCommandError(CommandsExtension commandSystem, CommandErroredEventArgs e)
{
return attr switch
switch (e.Exception)
{
SlashRequireDirectMessageAttribute => "This command can only be used in direct messages!",
SlashRequireOwnerAttribute => "Only the server owner can use that command!",
SlashRequirePermissionsAttribute => "You don't have permission to do that!",
SlashRequireBotPermissionsAttribute => "The bot doesn't have the required permissions to do that!",
SlashRequireUserPermissionsAttribute => "You don't have permission to do that!",
SlashRequireGuildAttribute => "This command has to be used in a Discord server!",
_ => "Unknown Discord API error occured, please try again later."
};
case ChecksFailedException checksFailedException:
{
foreach (ContextCheckFailedData error in checksFailedException.Errors)
{
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = error.ErrorMessage
});
}
return;
}
case BadRequestException ex:
Logger.Error("Command exception occured:\n" + e.Exception);
Logger.Error("JSON Message: " + ex.JsonMessage);
return;
default:
{
Logger.Error("Exception occured: " + e.Exception.GetType() + ": " + e.Exception);
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Internal error occured, please report this to the developer."
});
return;
}
}
}
}

View file

@ -10,7 +10,7 @@ public static class Logger
{
try
{
SupportChild.discordClient.Logger.Log(LogLevel.Debug, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
SupportChild.client.Logger.Log(LogLevel.Debug, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
}
catch (NullReferenceException)
{
@ -22,7 +22,7 @@ public static class Logger
{
try
{
SupportChild.discordClient.Logger.Log(LogLevel.Information, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
SupportChild.client.Logger.Log(LogLevel.Information, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
}
catch (NullReferenceException)
{
@ -34,7 +34,7 @@ public static class Logger
{
try
{
SupportChild.discordClient.Logger.Log(LogLevel.Warning, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
SupportChild.client.Logger.Log(LogLevel.Warning, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
}
catch (NullReferenceException)
{
@ -46,7 +46,7 @@ public static class Logger
{
try
{
SupportChild.discordClient.Logger.Log(LogLevel.Error, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
SupportChild.client.Logger.Log(LogLevel.Error, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
}
catch (NullReferenceException)
{
@ -58,7 +58,7 @@ public static class Logger
{
try
{
SupportChild.discordClient.Logger.Log(LogLevel.Critical, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
SupportChild.client.Logger.Log(LogLevel.Critical, new EventId(420, Assembly.GetEntryAssembly()?.GetName().Name), message);
}
catch (NullReferenceException)
{

View file

@ -8,31 +8,24 @@ using DSharpPlus;
using DSharpPlus.Interactivity;
using DSharpPlus.Interactivity.Enums;
using DSharpPlus.Interactivity.Extensions;
using DSharpPlus.SlashCommands;
using DSharpPlus.Commands;
using Microsoft.Extensions.Logging;
using SupportChild.Commands;
using CommandLine;
using DSharpPlus.Commands.ContextChecks;
using DSharpPlus.Commands.EventArgs;
using DSharpPlus.Commands.Exceptions;
using DSharpPlus.Commands.Processors.SlashCommands;
using DSharpPlus.Commands.Processors.TextCommands.Parsing;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using Microsoft.Extensions.DependencyInjection;
namespace SupportChild;
internal static class SupportChild
{
// Sets up a dummy client to use for logging
private static readonly DiscordConfiguration config = new()
{
Token = "DUMMY_TOKEN",
TokenType = TokenType.Bot,
MinimumLogLevel = LogLevel.Debug,
AutoReconnect = true,
Intents = DiscordIntents.All,
LogTimestampFormat = "yyyy-MM-dd HH:mm:ss",
LogUnknownEvents = false
};
public static DiscordClient discordClient { get; private set; } = new(config);
private static SlashCommandsExtension commands = null;
internal static DiscordClient client = null;
public class CommandLineArguments
{
[CommandLine.Option('c',
@ -124,10 +117,10 @@ internal static class SupportChild
public static async void Reload()
{
if (discordClient != null)
if (client != null)
{
await discordClient.DisconnectAsync();
discordClient.Dispose();
await client.DisconnectAsync();
client.Dispose();
}
Config.LoadConfig();
@ -152,78 +145,103 @@ internal static class SupportChild
throw;
}
try
{
Logger.Log("Connecting to database... (" + Config.hostName + ":" + Config.port + ")");
Interviewer.ParseConfig(Config.interviews);
Interviewer.LoadActiveInterviews();
}
catch (Exception e)
{
Logger.Fatal("Could not set up database tables, please confirm connection settings, status of the server and permissions of MySQL user. Error: " + e);
throw;
}
Logger.Log("Setting up Discord client...");
DiscordClientBuilder clientBuilder = DiscordClientBuilder.CreateDefault(Config.token, DiscordIntents.All)
.SetReconnectOnFatalGatewayErrors()
.SetLogLevel(Config.logLevel)
.ConfigureServices(configure =>
{
configure.AddSingleton<IClientErrorHandler>(new ErrorHandler());
})
.ConfigureEventHandlers(builder =>
{
builder.HandleGuildDownloadCompleted(EventHandler.OnReady);
builder.HandleGuildAvailable(EventHandler.OnGuildAvailable);
builder.HandleMessageCreated(EventHandler.OnMessageCreated);
builder.HandleGuildMemberAdded(EventHandler.OnMemberAdded);
builder.HandleGuildMemberRemoved(EventHandler.OnMemberRemoved);
builder.HandleComponentInteractionCreated(EventHandler.OnComponentInteractionCreated);
})
.UseInteractivity(new InteractivityConfiguration
{
PaginationBehaviour = PaginationBehaviour.Ignore,
PaginationDeletion = PaginationDeletion.DeleteMessage,
Timeout = TimeSpan.FromMinutes(15)
})
.UseCommands((_, extension) =>
{
extension.AddCommands(
[
typeof(AddCategoryCommand),
typeof(AddCommand),
typeof(AddMessageCommand),
typeof(AddStaffCommand),
typeof(AssignCommand),
typeof(BlacklistCommand),
typeof(CloseCommand),
typeof(CreateButtonPanelCommand),
typeof(CreateSelectionBoxPanelCommand),
typeof(ListAssignedCommand),
typeof(ListCommand),
typeof(ListOpen),
typeof(ListUnassignedCommand),
typeof(MoveCommand),
typeof(NewCommand),
typeof(RandomAssignCommand),
typeof(RemoveCategoryCommand),
typeof(RemoveMessageCommand),
typeof(RemoveStaffCommand),
typeof(SayCommand),
typeof(SetSummaryCommand),
typeof(StatusCommand),
typeof(SummaryCommand),
typeof(ToggleActiveCommand),
typeof(TranscriptCommand),
typeof(UnassignCommand),
typeof(UnblacklistCommand),
typeof(AdminCommands)
]);
extension.AddProcessor(new SlashCommandProcessor());
extension.CommandErrored += EventHandler.OnCommandError;
}, new CommandsConfiguration()
{
RegisterDefaultCommandProcessors = false,
UseDefaultCommandErrorHandler = false
})
.ConfigureExtraFeatures(clientConfig =>
{
clientConfig.LogUnknownEvents = false;
clientConfig.LogUnknownAuditlogs = false;
});
// Setting up client configuration
config.Token = Config.token;
config.MinimumLogLevel = Config.logLevel;
discordClient = new DiscordClient(config);
Logger.Log("Hooking events...");
discordClient.Ready += EventHandler.OnReady;
discordClient.GuildAvailable += EventHandler.OnGuildAvailable;
discordClient.ClientErrored += EventHandler.OnClientError;
discordClient.MessageCreated += EventHandler.OnMessageCreated;
discordClient.GuildMemberAdded += EventHandler.OnMemberAdded;
discordClient.GuildMemberRemoved += EventHandler.OnMemberRemoved;
discordClient.ComponentInteractionCreated += EventHandler.OnComponentInteractionCreated;
discordClient.UseInteractivity(new InteractivityConfiguration
{
PaginationBehaviour = PaginationBehaviour.Ignore,
PaginationDeletion = PaginationDeletion.DeleteMessage,
Timeout = TimeSpan.FromMinutes(15)
});
Logger.Log("Registering commands...");
commands = discordClient.UseSlashCommands();
commands.RegisterCommands<AddCategoryCommand>();
commands.RegisterCommands<AddCommand>();
commands.RegisterCommands<AddMessageCommand>();
commands.RegisterCommands<AddStaffCommand>();
commands.RegisterCommands<AssignCommand>();
commands.RegisterCommands<BlacklistCommand>();
commands.RegisterCommands<CloseCommand>();
commands.RegisterCommands<CreateButtonPanelCommand>();
commands.RegisterCommands<CreateSelectionBoxPanelCommand>();
commands.RegisterCommands<ListAssignedCommand>();
commands.RegisterCommands<ListCommand>();
commands.RegisterCommands<ListOpen>();
commands.RegisterCommands<ListUnassignedCommand>();
commands.RegisterCommands<MoveCommand>();
commands.RegisterCommands<NewCommand>();
commands.RegisterCommands<RandomAssignCommand>();
commands.RegisterCommands<RemoveCategoryCommand>();
commands.RegisterCommands<RemoveMessageCommand>();
commands.RegisterCommands<RemoveStaffCommand>();
commands.RegisterCommands<SayCommand>();
commands.RegisterCommands<SetSummaryCommand>();
commands.RegisterCommands<StatusCommand>();
commands.RegisterCommands<SummaryCommand>();
commands.RegisterCommands<ToggleActiveCommand>();
commands.RegisterCommands<TranscriptCommand>();
commands.RegisterCommands<UnassignCommand>();
commands.RegisterCommands<UnblacklistCommand>();
commands.RegisterCommands<AdminCommands>();
Logger.Log("Hooking command events...");
commands.SlashCommandErrored += EventHandler.OnCommandError;
client = clientBuilder.Build();
Logger.Log("Connecting to Discord...");
await discordClient.ConnectAsync();
await client.ConnectAsync();
}
}
internal class ErrorHandler : IClientErrorHandler
{
public ValueTask HandleEventHandlerError(string name, Exception exception, Delegate invokedDelegate, object sender, object args)
{
Logger.Error("Client exception occured:\n" + exception);
switch (exception)
{
case BadRequestException ex:
Logger.Error("JSON Message: " + ex.JsonMessage);
break;
default:
break;
}
return ValueTask.FromException(exception);
}
public ValueTask HandleGatewayError(Exception exception)
{
Logger.Error("A gateway error occured:\n" + exception);
return ValueTask.FromException(exception);
}
}

View file

@ -31,9 +31,9 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="DSharpPlus" Version="4.5.0" />
<PackageReference Include="DSharpPlus.Interactivity" Version="4.5.0" />
<PackageReference Include="DSharpPlus.SlashCommands" Version="4.5.0" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02397" />
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02397" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02397" />
<PackageReference Include="EmbeddedBuildTime" Version="1.0.3" />
<PackageReference Include="GitInfo" Version="3.3.5">
<PrivateAssets>all</PrivateAssets>

View file

@ -50,7 +50,7 @@ public static class Utilities
DiscordChannel channel = null;
try
{
channel = await SupportChild.discordClient.GetChannelAsync(category.id);
channel = await SupportChild.client.GetChannelAsync(category.id);
}
catch (Exception) { /*ignored*/ }