Fixed some stuff

Signed-off-by: Emotion <emotion@elliebot.net>
This commit is contained in:
Emotion 2023-03-24 01:21:20 +13:00
parent b4e833404c
commit acf63a745b
No known key found for this signature in database
GPG key ID: 15EBDFF858B9A65A
9 changed files with 1075 additions and 1064 deletions

View file

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using DSharpPlus.Entities; using DSharpPlus.Entities;
using DSharpPlus.SlashCommands; using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes; using DSharpPlus.SlashCommands.Attributes;
using MySql.Data.MySqlClient; using MySqlConnector;
namespace SupportChild.Commands; namespace SupportChild.Commands;

View file

@ -86,7 +86,7 @@ public class CloseCommand : ApplicationCommandModule
await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read); await using FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read);
DiscordMessageBuilder message = new DiscordMessageBuilder(); DiscordMessageBuilder message = new DiscordMessageBuilder();
message.WithEmbed(embed); message.WithEmbed(embed);
message.WithFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } }); message.AddFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } });
await logChannel.SendMessageAsync(message); await logChannel.SendMessageAsync(message);
} }
@ -107,7 +107,7 @@ public class CloseCommand : ApplicationCommandModule
DiscordMessageBuilder message = new DiscordMessageBuilder(); DiscordMessageBuilder message = new DiscordMessageBuilder();
message.WithEmbed(embed); message.WithEmbed(embed);
message.WithFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } }); message.AddFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } });
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }

View file

@ -105,7 +105,7 @@ public class NewCommand : ApplicationCommandModule
case ComponentType.Button: case ComponentType.Button:
stringID = interaction.Data.CustomId.Replace("supportchild_newcommandbutton ", ""); stringID = interaction.Data.CustomId.Replace("supportchild_newcommandbutton ", "");
break; break;
case ComponentType.Select: case ComponentType.StringSelect:
if (interaction.Data.Values == null || interaction.Data.Values.Length <= 0) return; if (interaction.Data.Values == null || interaction.Data.Values.Length <= 0) return;
stringID = interaction.Data.Values[0]; stringID = interaction.Data.Values[0];
break; break;

View file

@ -2,7 +2,7 @@
using DSharpPlus.Entities; using DSharpPlus.Entities;
using DSharpPlus.SlashCommands; using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes; using DSharpPlus.SlashCommands.Attributes;
using MySql.Data.MySqlClient; using MySqlConnector;
namespace SupportChild.Commands; namespace SupportChild.Commands;

View file

@ -2,7 +2,7 @@
using DSharpPlus.Entities; using DSharpPlus.Entities;
using DSharpPlus.SlashCommands; using DSharpPlus.SlashCommands;
using DSharpPlus.SlashCommands.Attributes; using DSharpPlus.SlashCommands.Attributes;
using MySql.Data.MySqlClient; using MySqlConnector;
namespace SupportChild.Commands; namespace SupportChild.Commands;

View file

@ -90,7 +90,7 @@ public class TranscriptCommand : ApplicationCommandModule
Description = "Ticket " + ticket.id.ToString("00000") + " transcript generated by " + command.Member.Mention + ".\n", Description = "Ticket " + ticket.id.ToString("00000") + " transcript generated by " + command.Member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + command.Channel.Name } Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + command.Channel.Name }
}); });
message.WithFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } }); message.AddFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } });
await logChannel.SendMessageAsync(message); await logChannel.SendMessageAsync(message);
} }
@ -106,7 +106,7 @@ public class TranscriptCommand : ApplicationCommandModule
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Transcript generated!\n" Description = "Transcript generated!\n"
}); });
directMessage.WithFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } }); directMessage.AddFiles(new Dictionary<string, Stream> { { Transcriber.GetFilename(ticket.id), file } });
await command.Member.SendMessageAsync(directMessage); await command.Member.SendMessageAsync(directMessage);
} }

File diff suppressed because it is too large Load diff

View file

@ -14,262 +14,272 @@ namespace SupportChild;
internal static class EventHandler internal static class EventHandler
{ {
internal static Task OnReady(DiscordClient client, ReadyEventArgs e) internal static Task OnReady(DiscordClient client, ReadyEventArgs e)
{ {
Logger.Log("Client is ready to process events."); Logger.Log("Client is ready to process events.");
// Checking activity type // Checking activity type
if (!Enum.TryParse(Config.presenceType, true, out ActivityType activityType)) if (!Enum.TryParse(Config.presenceType, true, out ActivityType activityType))
{ {
Logger.Log("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead."); Logger.Log("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead.");
activityType = ActivityType.Playing; activityType = ActivityType.Playing;
} }
client.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online); client.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online);
return Task.CompletedTask; return Task.CompletedTask;
} }
internal static Task OnGuildAvailable(DiscordClient _, GuildCreateEventArgs e) internal static Task OnGuildAvailable(DiscordClient _, GuildCreateEventArgs e)
{ {
Logger.Log("Guild available: " + e.Guild.Name); Logger.Log("Guild available: " + e.Guild.Name);
IReadOnlyDictionary<ulong, DiscordRole> roles = e.Guild.Roles; IReadOnlyDictionary<ulong, DiscordRole> roles = e.Guild.Roles;
foreach ((ulong roleID, DiscordRole role) in roles) foreach ((ulong roleID, DiscordRole role) in roles)
{ {
Logger.Log(role.Name.PadRight(40, '.') + roleID); Logger.Log(role.Name.PadRight(40, '.') + roleID);
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
internal static Task OnClientError(DiscordClient _, ClientErrorEventArgs e) internal static Task OnClientError(DiscordClient _, ClientErrorEventArgs e)
{ {
Logger.Error("Client exception occured:\n" + e.Exception); Logger.Error("Client exception occured:\n" + e.Exception);
switch (e.Exception) switch (e.Exception)
{ {
case BadRequestException ex: case BadRequestException ex:
Logger.Error("JSON Message: " + ex.JsonMessage); Logger.Error("JSON Message: " + ex.JsonMessage);
break; break;
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
internal static async Task OnMessageCreated(DiscordClient client, MessageCreateEventArgs e) internal static async Task OnMessageCreated(DiscordClient client, MessageCreateEventArgs e)
{ {
if (e.Author.IsBot) if (e.Author.IsBot)
{ {
return; return;
} }
// Check if ticket exists in the database and ticket notifications are enabled // Check if ticket exists in the database and ticket notifications are enabled
if (!Database.TryGetOpenTicket(e.Channel.Id, out Database.Ticket ticket) || !Config.ticketUpdatedNotifications) if (!Database.TryGetOpenTicket(e.Channel.Id, out Database.Ticket ticket) || !Config.ticketUpdatedNotifications)
{ {
return; return;
} }
// 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 // 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); IReadOnlyList<DiscordMessage> messages = await e.Channel.GetMessagesAsync(2);
if (messages.Count > 1 && messages[1].Timestamp < DateTimeOffset.UtcNow.AddDays(Config.ticketUpdatedNotificationDelay * -1) && !Database.IsStaff(e.Author.Id)) if (messages.Count > 1 && messages[1].Timestamp < DateTimeOffset.UtcNow.AddDays(Config.ticketUpdatedNotificationDelay * -1) && !Database.IsStaff(e.Author.Id))
{ {
try try
{ {
DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID); DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID);
await staffMember.SendMessageAsync(new DiscordEmbedBuilder await staffMember.SendMessageAsync(new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "A ticket you are assigned to has been updated: " + e.Channel.Mention Description = "A ticket you are assigned to has been updated: " + e.Channel.Mention
}); });
} }
catch (NotFoundException) { } catch (NotFoundException) { }
catch (UnauthorizedException) { } catch (UnauthorizedException) { }
} }
} }
internal static async Task OnCommandError(SlashCommandsExtension commandSystem, SlashCommandErrorEventArgs e) internal static async Task OnCommandError(SlashCommandsExtension commandSystem, SlashCommandErrorEventArgs e)
{ {
switch (e.Exception) switch (e.Exception)
{ {
case SlashExecutionChecksFailedException checksFailedException: case SlashExecutionChecksFailedException checksFailedException:
{ {
foreach (SlashCheckBaseAttribute attr in checksFailedException.FailedChecks) foreach (SlashCheckBaseAttribute attr in checksFailedException.FailedChecks)
{ {
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = ParseFailedCheck(attr) Description = ParseFailedCheck(attr)
}); });
} }
return; return;
} }
case BadRequestException ex: case BadRequestException ex:
Logger.Error("Command exception occured:\n" + e.Exception); Logger.Error("Command exception occured:\n" + e.Exception);
Logger.Error("JSON Message: " + ex.JsonMessage); Logger.Error("JSON Message: " + ex.JsonMessage);
return; return;
default: default:
{ {
Logger.Error("Exception occured: " + e.Exception.GetType() + ": " + e.Exception); Logger.Error("Exception occured: " + e.Exception.GetType() + ": " + e.Exception);
await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder await e.Context.Channel.SendMessageAsync(new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Internal error occured, please report this to the developer." Description = "Internal error occured, please report this to the developer."
}); });
return; return;
} }
} }
} }
internal static async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e) internal static async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
{ {
if (!Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets)) if (!Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{ {
return; return;
} }
foreach (Database.Ticket ticket in ownTickets) foreach (Database.Ticket ticket in ownTickets)
{ {
try try
{ {
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID); DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id) if (channel?.GuildId == e.Guild.Id)
{ {
await channel.SendMessageAsync(new DiscordEmbedBuilder try
{ {
Color = DiscordColor.Green, await channel.AddOverwriteAsync(e.Member, Permissions.AccessChannels);
Description = "User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket." await channel.SendMessageAsync(new DiscordEmbedBuilder
}); {
} Color = DiscordColor.Green,
} Description = "User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket."
catch (Exception) { /* ignored */ } });
} }
} catch (DiscordException ex)
{
Logger.Error("Exception occurred trying to add channel permissions: " + ex);
Logger.Error("JsomMessage: " + ex.JsonMessage);
}
internal static async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e) }
{ }
if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets)) catch (Exception) { /* ignored */ }
{ }
foreach (Database.Ticket ticket in ownTickets) }
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
await channel.SendMessageAsync(new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server."
});
}
}
catch (Exception) { /* ignored */ }
}
}
if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0) internal static async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e)
{ {
DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel); if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
if (logChannel != null) {
{ foreach (Database.Ticket ticket in ownTickets)
foreach (Database.Ticket ticket in assignedTickets) {
{ try
try {
{ DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID); if (channel?.GuildId == e.Guild.Id)
if (channel?.GuildId == e.Guild.Id) {
{ await channel.SendMessageAsync(new DiscordEmbedBuilder
await logChannel.SendMessageAsync(new DiscordEmbedBuilder {
{ Color = DiscordColor.Red,
Color = DiscordColor.Red, Description = "User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server."
Description = "Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">" });
}); }
} }
} catch (Exception) { /* ignored */ }
catch (Exception) { /* ignored */ } }
} }
}
}
}
internal static async Task OnComponentInteractionCreated(DiscordClient client, ComponentInteractionCreateEventArgs e) if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0)
{ {
try DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel);
{ if (logChannel != null)
switch (e.Interaction.Data.ComponentType) {
{ foreach (Database.Ticket ticket in assignedTickets)
case ComponentType.Button: {
switch (e.Id) try
{ {
case "supportchild_closeconfirm": DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
await CloseCommand.OnConfirmed(e.Interaction); if (channel?.GuildId == e.Guild.Id)
return; {
case { } when e.Id.StartsWith("supportchild_newcommandbutton"): await logChannel.SendMessageAsync(new DiscordEmbedBuilder
await NewCommand.OnCategorySelection(e.Interaction); {
return; Color = DiscordColor.Red,
case { } when e.Id.StartsWith("supportchild_newticketbutton"): Description = "Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">"
await CreateButtonPanelCommand.OnButtonUsed(e.Interaction); });
return; }
case "right": }
return; catch (Exception) { /* ignored */ }
case "left": }
return; }
case "rightskip": }
return; }
case "leftskip":
return;
case "stop":
return;
default:
Logger.Warn("Unknown button press received! '" + e.Id + "'");
return;
}
case ComponentType.Select:
switch (e.Id)
{
case { } when e.Id.StartsWith("supportchild_newcommandselector"):
await NewCommand.OnCategorySelection(e.Interaction);
return;
case { } 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:
Logger.Warn("Unknown action row received! '" + e.Id + "'");
return;
case ComponentType.FormInput:
Logger.Warn("Unknown form input received! '" + e.Id + "'");
return;
default:
Logger.Warn("Unknown interaction type received! '" + e.Interaction.Data.ComponentType + "'");
break;
}
}
catch (DiscordException ex)
{
Logger.Error("Interaction Exception occurred: " + ex);
Logger.Error("JsomMessage: " + ex.JsonMessage);
}
catch (Exception ex)
{
Logger.Error("Interaction Exception occured: " + ex.GetType() + ": " + ex);
}
}
private static string ParseFailedCheck(SlashCheckBaseAttribute attr) internal static async Task OnComponentInteractionCreated(DiscordClient client, ComponentInteractionCreateEventArgs e)
{ {
return attr switch try
{ {
SlashRequireDirectMessageAttribute => "This command can only be used in direct messages!", switch (e.Interaction.Data.ComponentType)
SlashRequireOwnerAttribute => "Only the server owner can use that command!", {
SlashRequirePermissionsAttribute => "You don't have permission to do that!", case ComponentType.Button:
SlashRequireBotPermissionsAttribute => "The bot doesn't have the required permissions to do that!", switch (e.Id)
SlashRequireUserPermissionsAttribute => "You don't have permission to do that!", {
SlashRequireGuildAttribute => "This command has to be used in a Discord server!", case "supportchild_closeconfirm":
_ => "Unknown Discord API error occured, please try again later." await CloseCommand.OnConfirmed(e.Interaction);
}; return;
} case { } when e.Id.StartsWith("supportchild_newcommandbutton"):
await NewCommand.OnCategorySelection(e.Interaction);
return;
case { } when e.Id.StartsWith("supportchild_newticketbutton"):
await CreateButtonPanelCommand.OnButtonUsed(e.Interaction);
return;
case "right":
return;
case "left":
return;
case "rightskip":
return;
case "leftskip":
return;
case "stop":
return;
default:
Logger.Warn("Unknown button press received! '" + e.Id + "'");
return;
}
case ComponentType.StringSelect:
switch (e.Id)
{
case { } when e.Id.StartsWith("supportchild_newcommandselector"):
await NewCommand.OnCategorySelection(e.Interaction);
return;
case { } 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:
Logger.Warn("Unknown action row received! '" + e.Id + "'");
return;
case ComponentType.FormInput:
Logger.Warn("Unknown form input received! '" + e.Id + "'");
return;
default:
Logger.Warn("Unknown interaction type received! '" + e.Interaction.Data.ComponentType + "'");
break;
}
}
catch (DiscordException ex)
{
Logger.Error("Interaction Exception occurred: " + ex);
Logger.Error("JsomMessage: " + ex.JsonMessage);
}
catch (Exception ex)
{
Logger.Error("Interaction Exception occured: " + ex.GetType() + ": " + ex);
}
}
private static string ParseFailedCheck(SlashCheckBaseAttribute attr)
{
return attr switch
{
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."
};
}
} }

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@ -16,8 +16,8 @@
<PackageIconUrl>https://cdn.discordapp.com/attachments/765441543100170271/914327948667011132/Ellie_Concept_2_transparent_ver.png</PackageIconUrl> <PackageIconUrl>https://cdn.discordapp.com/attachments/765441543100170271/914327948667011132/Ellie_Concept_2_transparent_ver.png</PackageIconUrl>
<Description>A Discord support ticket bot built for the Ellie's home server</Description> <Description>A Discord support ticket bot built for the Ellie's home server</Description>
<NeutralLanguage>en</NeutralLanguage> <NeutralLanguage>en</NeutralLanguage>
<Version>1.3.0</Version> <Version>1.3.1</Version>
<PackageVersion>1.3.0</PackageVersion> <PackageVersion>1.3.1</PackageVersion>
<AssemblyVersion>3.0.0.1</AssemblyVersion> <AssemblyVersion>3.0.0.1</AssemblyVersion>
<FileVersion>3.0.0.1</FileVersion> <FileVersion>3.0.0.1</FileVersion>
</PropertyGroup> </PropertyGroup>
@ -27,19 +27,19 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DSharpPlus" Version="4.2.0" /> <PackageReference Include="DSharpPlus" Version="4.4.0-nightly-01249" />
<PackageReference Include="DSharpPlus.Interactivity" Version="4.2.0" /> <PackageReference Include="DSharpPlus.Interactivity" Version="4.4.0-nightly-01249" />
<PackageReference Include="DSharpPlus.SlashCommands" Version="4.2.0" /> <PackageReference Include="DSharpPlus.SlashCommands" Version="4.4.0-nightly-01249" />
<PackageReference Include="Gress" Version="2.0.1" /> <PackageReference Include="Gress" Version="2.0.1" />
<PackageReference Include="JsonExtensions" Version="1.2.0" /> <PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="MiniRazor.CodeGen" Version="2.2.2" /> <PackageReference Include="MiniRazor.CodeGen" Version="2.2.2" />
<PackageReference Include="MySql.Data" Version="8.0.30" /> <PackageReference Include="MySqlConnector" Version="2.2.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Polly" Version="7.2.3" /> <PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Superpower" Version="3.0.0" /> <PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="Tyrrrz.Extensions" Version="1.6.5" /> <PackageReference Include="Tyrrrz.Extensions" Version="1.6.5" />
<PackageReference Include="WebMarkupMin.Core" Version="2.13.0" /> <PackageReference Include="WebMarkupMin.Core" Version="2.13.0" />
<PackageReference Include="YamlDotNet" Version="12.2.1" /> <PackageReference Include="YamlDotNet" Version="12.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>