1.2.0 update

Updated and fixed some stuff
This commit is contained in:
Emotion 2022-05-20 02:06:32 +12:00 committed by GitHub
commit 8f2f03a99b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 3019 additions and 3018 deletions

View file

@ -1,4 +1,4 @@
# To get started with Dependabot version updates, you'll need to specify which # To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located. # package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options: # Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
@ -12,7 +12,7 @@ updates:
open-pull-requests-limit: 5 open-pull-requests-limit: 5
reviewers: reviewers:
- EmotionChild - EmotionChild
target-branch: "main" target-branch: "development"
labels: labels:
- "nuget" - "nuget"
- "dependencies" - "dependencies"

View file

@ -1,4 +1,4 @@
name: .NET name: .NET
on: on:
push: push:
@ -12,14 +12,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v2 uses: actions/setup-dotnet@v2
with: with:
dotnet-version: 6.0.x dotnet-version: 6.0.x
- name: Restore dependencies - name: Restore dependencies
run: dotnet restore run: dotnet restore
- name: Build - name: Build
run: dotnet build --no-restore run: dotnet build --no-restore
- name: Test - name: Test
run: dotnet test --no-build --verbosity normal run: dotnet test --no-build --verbosity normal

3
.gitignore vendored
View file

@ -362,5 +362,8 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
# Manually added folders
Windows-x64/ Windows-x64/
Linux-x64/ Linux-x64/
.idea
.vs

View file

@ -1 +1,3 @@
# SupportChild # SupportChild
this is a customized version of [SupportBoi](https://github.com/KarlOfDuty/SupportBoi) it is recommended you go and check out the awesome work that is there!

View file

@ -1,9 +1,6 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SupportChild", "SupportChild\SupportChild.csproj", "{B043AACB-D763-4C61-9524-C8B7C58DA3EF}"
VisualStudioVersion = 17.0.32126.317
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SupportChild", "SupportChild\SupportChild.csproj", "{9124DF58-D261-4906-8ECA-D853DEBE07D4}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -11,15 +8,9 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Release|Any CPU.ActiveCfg = Release|Any CPU {B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Release|Any CPU.Build.0 = Release|Any CPU {B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B2CD3447-A8BA-4B02-9E08-A75CBBD2BDCB}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -0,0 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">ERROR</s:String>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=SupportChild_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean>
</wpf:ResourceDictionary>

View file

@ -8,100 +8,100 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class AddCommand : BaseCommandModule public class AddCommand : BaseCommandModule
{ {
[Command("add")] [Command("add")]
[Description("Adds a user to a ticket.")] [Description("Adds a user to a ticket.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "add")) if (!Config.HasPermission(command.Member, "add"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the add command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the add command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.IsOpenTicket(command.Channel.Id)) if (!Database.IsOpenTicket(command.Channel.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString); string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString);
foreach (string parsedArg in parsedArgs) foreach (string parsedArg in parsedArgs)
{ {
if (!ulong.TryParse(parsedArg, out ulong userID)) if (!ulong.TryParse(parsedArg, out ulong userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
continue; continue;
} }
DiscordMember mentionedMember; DiscordMember mentionedMember;
try try
{ {
mentionedMember = await command.Guild.GetMemberAsync(userID); mentionedMember = await command.Guild.GetMemberAsync(userID);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not find user on this server)" Description = "Invalid ID/Mention. (Could not find user on this server)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
continue; continue;
} }
try try
{ {
await command.Channel.AddOverwriteAsync(mentionedMember, Permissions.AccessChannels, Permissions.None); await command.Channel.AddOverwriteAsync(mentionedMember, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Added " + mentionedMember.Mention + " to ticket." Description = "Added " + mentionedMember.Mention + " to ticket."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = mentionedMember.Mention + " was added to " + command.Channel.Mention + Description = mentionedMember.Mention + " was added to " + command.Channel.Mention +
" by " + command.Member.Mention + "." " by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Could not add <@" + parsedArg + "> to ticket, unknown error occured." Description = "Could not add <@" + parsedArg + "> to ticket, unknown error occured."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
} }
} }
} }
} }
} }

View file

@ -39,7 +39,7 @@ namespace SupportChild.Commands
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (Database.TryGetMessage(identifier.ToLower(), out Database.Message _)) if (Database.TryGetMessage(identifier.ToLower(), out Database.Message _))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
@ -51,7 +51,7 @@ namespace SupportChild.Commands
return; return;
} }
if (Database.AddMessage(identifier, command.Member.Id, message)) if(Database.AddMessage(identifier, command.Member.Id, message))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
@ -71,7 +71,6 @@ namespace SupportChild.Commands
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
} }
} }
} }

View file

@ -9,88 +9,88 @@ using MySql.Data.MySqlClient;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class AddStaffCommand : BaseCommandModule public class AddStaffCommand : BaseCommandModule
{ {
[Command("addstaff")] [Command("addstaff")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "addstaff")) if (!Config.HasPermission(command.Member, "addstaff"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the addstaff command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the addstaff command but did not have permission.");
return; return;
} }
ulong userID; ulong userID;
string[] parsedArgs = Utilities.ParseIDs(commandArgs); string[] parsedArgs = Utilities.ParseIDs(commandArgs);
if (!parsedArgs.Any()) if (!parsedArgs.Any())
{ {
userID = command.Member.Id; userID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedArgs[0], out userID)) else if (!ulong.TryParse(parsedArgs[0], out userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordMember member; DiscordMember member;
try try
{ {
member = await command.Guild.GetMemberAsync(userID); member = await command.Guild.GetMemberAsync(userID);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not find user on this server)" Description = "Invalid ID/Mention. (Could not find user on this server)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
using (MySqlConnection c = Database.GetConnection()) using (MySqlConnection c = Database.GetConnection())
{ {
MySqlCommand cmd = Database.IsStaff(userID) ? new MySqlCommand(@"UPDATE staff SET name = @name WHERE user_id = @user_id", c) : new MySqlCommand(@"INSERT INTO staff (user_id, name) VALUES (@user_id, @name);", c); MySqlCommand cmd = Database.IsStaff(userID) ? new MySqlCommand(@"UPDATE staff SET name = @name WHERE user_id = @user_id", c) : new MySqlCommand(@"INSERT INTO staff (user_id, name) VALUES (@user_id, @name);", c);
c.Open(); c.Open();
cmd.Parameters.AddWithValue("@user_id", userID); cmd.Parameters.AddWithValue("@user_id", userID);
cmd.Parameters.AddWithValue("@name", member.DisplayName); cmd.Parameters.AddWithValue("@name", member.DisplayName);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
cmd.Dispose(); cmd.Dispose();
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = member.Mention + " was added to staff." Description = member.Mention + " was added to staff."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = member.Mention + " was added to staff.\n", Description = member.Mention + " was added to staff.\n",
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }
} }

View file

@ -8,128 +8,128 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class AssignCommand : BaseCommandModule public class AssignCommand : BaseCommandModule
{ {
[Command("assign")] [Command("assign")]
[Description("Assigns a staff member to a ticket.")] [Description("Assigns a staff member to a ticket.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "assign")) if (!Config.HasPermission(command.Member, "assign"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the assign command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the assign command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
ulong staffID; ulong staffID;
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedMessage.Any()) if (!parsedMessage.Any())
{ {
staffID = command.Member.Id; staffID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedMessage[0], out staffID)) else if (!ulong.TryParse(parsedMessage[0], out staffID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordMember staffMember = null; DiscordMember staffMember = null;
try try
{ {
staffMember = await command.Guild.GetMemberAsync(staffID); staffMember = await command.Guild.GetMemberAsync(staffID);
} }
catch (NotFoundException) { } catch (NotFoundException) { }
if (staffMember == null) if (staffMember == null)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Could not find user." Description = "Error: Could not find user."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (!Database.IsStaff(staffMember.Id)) if (!Database.IsStaff(staffMember.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: User is not registered as staff." Description = "Error: User is not registered as staff."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (!Database.AssignStaff(ticket, staffID)) if (!Database.AssignStaff(ticket, staffID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Failed to assign " + staffMember.Mention + " to ticket." Description = "Error: Failed to assign " + staffMember.Mention + " to ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordEmbed feedback = new DiscordEmbedBuilder DiscordEmbed feedback = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Assigned " + staffMember.Mention + " to ticket." Description = "Assigned " + staffMember.Mention + " to ticket."
}; };
await command.RespondAsync(feedback); await command.RespondAsync(feedback);
if (Config.assignmentNotifications) if (Config.assignmentNotifications)
{ {
try try
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "You have been assigned to a support ticket: " + command.Channel.Mention Description = "You have been assigned to a support ticket: " + command.Channel.Mention
}; };
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
catch (UnauthorizedException) { } catch (UnauthorizedException) {}
} }
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }

View file

@ -8,92 +8,92 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class BlacklistCommand : BaseCommandModule public class BlacklistCommand : BaseCommandModule
{ {
[Command("blacklist")] [Command("blacklist")]
[Description("Blacklists a user from opening tickets.")] [Description("Blacklists a user from opening tickets.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "blacklist")) if (!Config.HasPermission(command.Member, "blacklist"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the blacklist command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the blacklist command but did not have permission.");
return; return;
} }
string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString); string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString);
foreach (string parsedArg in parsedArgs) foreach (string parsedArg in parsedArgs)
{ {
if (ulong.TryParse(parsedArg, out ulong userId)) if (ulong.TryParse(parsedArg, out ulong userId))
{ {
DiscordUser blacklistedUser = null; DiscordUser blacklistedUser = null;
try try
{ {
blacklistedUser = await command.Client.GetUserAsync(userId); blacklistedUser = await command.Client.GetUserAsync(userId);
} }
catch (NotFoundException) { } catch (NotFoundException) { }
if (blacklistedUser == null) if (blacklistedUser == null)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Could not find user." Description = "Error: Could not find user."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
continue; continue;
} }
try try
{ {
if (!Database.Blacklist(blacklistedUser.Id, command.User.Id)) if (!Database.Blacklist(blacklistedUser.Id, command.User.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = blacklistedUser.Mention + " is already blacklisted." Description = blacklistedUser.Mention + " is already blacklisted."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
continue; continue;
} }
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Blacklisted " + blacklistedUser.Mention + "." Description = "Blacklisted " + blacklistedUser.Mention + "."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = blacklistedUser.Mention + " was blacklisted from opening tickets by " + command.Member.Mention + "." Description = blacklistedUser.Mention + " was blacklisted from opening tickets by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error occured while blacklisting " + blacklistedUser.Mention + "." Description = "Error occured while blacklisting " + blacklistedUser.Mention + "."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
throw; throw;
} }
} }
} }
} }
} }
} }

View file

@ -10,109 +10,109 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class CloseCommand : BaseCommandModule public class CloseCommand : BaseCommandModule
{ {
[Command("close")] [Command("close")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "close")) if (!Config.HasPermission(command.Member, "close"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the close command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the close command but did not have permission.");
return; return;
} }
ulong channelID = command.Channel.Id; ulong channelID = command.Channel.Id;
string channelName = command.Channel.Name; string channelName = command.Channel.Name;
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetOpenTicket(channelID, out Database.Ticket ticket)) if (!Database.TryGetOpenTicket(channelID, out Database.Ticket ticket))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
// Build transcript // Build transcript
try try
{ {
await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "ERROR: Could not save transcript file. Aborting..." Description = "ERROR: Could not save transcript file. Aborting..."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
throw; throw;
} }
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed embed = new DiscordEmbedBuilder DiscordEmbed embed = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket " + ticket.id.ToString("00000") + " closed by " + command.Member.Mention + ".\n", Description = "Ticket " + ticket.id.ToString("00000") + " closed by " + command.Member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName }
}; };
using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) 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.WithFiles(new Dictionary<string, Stream>() { { Transcriber.GetFilename(ticket.id), file } });
await logChannel.SendMessageAsync(message); await logChannel.SendMessageAsync(message);
} }
} }
if (Config.closingNotifications) if (Config.closingNotifications)
{ {
DiscordEmbed embed = new DiscordEmbedBuilder DiscordEmbed embed = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket " + ticket.id.ToString("00000") + " which you opened has now been closed, check the transcript for more info.\n", Description = "Ticket " + ticket.id.ToString("00000") + " which you opened has now been closed, check the transcript for more info.\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName } Footer = new DiscordEmbedBuilder.EmbedFooter { Text = '#' + channelName }
}; };
try try
{ {
DiscordMember staffMember = await command.Guild.GetMemberAsync(ticket.creatorID); DiscordMember staffMember = await command.Guild.GetMemberAsync(ticket.creatorID);
using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) 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.WithFiles(new Dictionary<string, Stream>() { { Transcriber.GetFilename(ticket.id), file } });
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
} }
catch (NotFoundException) { } catch (NotFoundException) { }
catch (UnauthorizedException) { } catch (UnauthorizedException) { }
} }
Database.ArchiveTicket(ticket); Database.ArchiveTicket(ticket);
// Delete the channel and database entry // Delete the channel and database entry
await command.Channel.DeleteAsync("Ticket closed."); await command.Channel.DeleteAsync("Ticket closed.");
Database.DeleteOpenTicket(ticket.id); Database.DeleteOpenTicket(ticket.id);
} }
} }
} }

View file

@ -8,69 +8,69 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class ListAssignedCommand : BaseCommandModule public class ListAssignedCommand : BaseCommandModule
{ {
[Command("listassigned")] [Command("listassigned")]
[Aliases("la")] [Aliases("la")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "listassigned")) if (!Config.HasPermission(command.Member, "listassigned"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the listassigned command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the listassigned command but did not have permission.");
return; return;
} }
ulong staffID; ulong staffID;
string[] parsedIDs = Utilities.ParseIDs(command.RawArgumentString); string[] parsedIDs = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedIDs.Any()) if (!parsedIDs.Any())
{ {
staffID = command.Member.Id; staffID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedIDs[0], out staffID)) else if (!ulong.TryParse(parsedIDs[0], out staffID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (!Database.TryGetAssignedTickets(staffID, out List<Database.Ticket> assignedTickets)) if (!Database.TryGetAssignedTickets(staffID, out List<Database.Ticket> assignedTickets))
{ {
DiscordEmbed error = new DiscordEmbedBuilder() DiscordEmbed error = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("User does not have any assigned tickets."); .WithDescription("User does not have any assigned tickets.");
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
List<string> listItems = new List<string>(); List<string> listItems = new List<string>();
foreach (Database.Ticket ticket in assignedTickets) foreach (Database.Ticket ticket in assignedTickets)
{ {
listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n");
} }
LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems); LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems);
foreach (string message in messages) foreach (string message in messages)
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithTitle("Assigned tickets: ") .WithTitle("Assigned tickets: ")
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription(message); .WithDescription(message);
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
} }
} }

View file

@ -8,94 +8,94 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class ListCommand : BaseCommandModule public class ListCommand : BaseCommandModule
{ {
[Command("list")] [Command("list")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "list")) if (!Config.HasPermission(command.Member, "list"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the list command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the list command but did not have permission.");
return; return;
} }
ulong userID; ulong userID;
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedMessage.Any()) if (!parsedMessage.Any())
{ {
userID = command.Member.Id; userID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedMessage[0], out userID)) else if (!ulong.TryParse(parsedMessage[0], out userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (Database.TryGetOpenTickets(userID, out List<Database.Ticket> openTickets)) if (Database.TryGetOpenTickets(userID, out List<Database.Ticket> openTickets))
{ {
List<string> listItems = new List<string>(); List<string> listItems = new List<string>();
foreach (Database.Ticket ticket in openTickets) foreach (Database.Ticket ticket in openTickets)
{ {
listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + ">\n"); listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + ">\n");
} }
LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems); LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems);
foreach (string message in messages) foreach (string message in messages)
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithTitle("Open tickets: ") .WithTitle("Open tickets: ")
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription(message); .WithDescription(message);
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
else else
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription("User does not have any open tickets."); .WithDescription("User does not have any open tickets.");
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
if (Database.TryGetClosedTickets(userID, out List<Database.Ticket> closedTickets)) if (Database.TryGetClosedTickets(userID, out List<Database.Ticket> closedTickets))
{ {
List<string> listItems = new List<string>(); List<string> listItems = new List<string>();
foreach (Database.Ticket ticket in closedTickets) foreach (Database.Ticket ticket in closedTickets)
{ {
listItems.Add("**" + ticket.FormattedCreatedTime() + ":** Ticket " + ticket.id.ToString("00000") + "\n"); listItems.Add("**" + ticket.FormattedCreatedTime() + ":** Ticket " + ticket.id.ToString("00000") + "\n");
} }
LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems); LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems);
foreach (string message in messages) foreach (string message in messages)
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithTitle("Closed tickets: ") .WithTitle("Closed tickets: ")
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription(message); .WithDescription(message);
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
else else
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("User does not have any closed tickets."); .WithDescription("User does not have any closed tickets.");
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
} }
} }

View file

@ -7,65 +7,65 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class ListOldestCommand : BaseCommandModule public class ListOldestCommand : BaseCommandModule
{ {
[Command("listoldest")] [Command("listoldest")]
[Aliases("lo")] [Aliases("lo")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "listoldest")) if (!Config.HasPermission(command.Member, "listoldest"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the listoldest command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the listoldest command but did not have permission.");
return; return;
} }
int listLimit = 20; int listLimit = 20;
if (!string.IsNullOrEmpty(command.RawArgumentString?.Trim() ?? "")) if (!string.IsNullOrEmpty(command.RawArgumentString?.Trim() ?? ""))
{ {
if (!int.TryParse(command.RawArgumentString?.Trim(), out listLimit) || listLimit < 5 || listLimit > 100) if (!int.TryParse(command.RawArgumentString?.Trim(), out listLimit) || listLimit < 5 || listLimit > 100)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid list amount. (Must be an integer between 5 and 100)" Description = "Invalid list amount. (Must be integer between 5 and 100)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
} }
if (!Database.TryGetOldestTickets(command.Member.Id, out List<Database.Ticket> openTickets, listLimit)) if (!Database.TryGetOldestTickets(command.Member.Id, out List<Database.Ticket> openTickets, listLimit))
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("Could not fetch any open tickets."); .WithDescription("Could not fetch any open tickets.");
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
return; return;
} }
List<string> listItems = new List<string>(); List<string> listItems = new List<string>();
foreach (Database.Ticket ticket in openTickets) foreach (Database.Ticket ticket in openTickets)
{ {
listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n"); listItems.Add("**" + ticket.FormattedCreatedTime() + ":** <#" + ticket.channelID + "> by <@" + ticket.creatorID + ">\n");
} }
LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems); LinkedList<string> messages = Utilities.ParseListIntoMessages(listItems);
foreach (string message in messages) foreach (string message in messages)
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithTitle("The " + openTickets.Count + " oldest open tickets: ") .WithTitle("The " + openTickets.Count + " oldest open tickets: ")
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription(message?.Trim()); .WithDescription(message?.Trim());
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
} }
} }

View file

@ -52,4 +52,4 @@ namespace SupportChild.Commands
} }
} }
} }
} }

View file

@ -10,95 +10,95 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class MoveCommand : BaseCommandModule public class MoveCommand : BaseCommandModule
{ {
[Command("move")] [Command("move")]
[Description("Moves a ticket to another category.")] [Description("Moves a ticket to another category.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "move")) if (!Config.HasPermission(command.Member, "move"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the move command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the move command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (string.IsNullOrEmpty(command.RawArgumentString)) if (string.IsNullOrEmpty(command.RawArgumentString))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: No category provided." Description = "Error: No category provided."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
IReadOnlyList<DiscordChannel> channels = await command.Guild.GetChannelsAsync(); IReadOnlyList<DiscordChannel> channels = await command.Guild.GetChannelsAsync();
IEnumerable<DiscordChannel> categories = channels.Where(x => x.IsCategory); IEnumerable<DiscordChannel> categories = channels.Where(x => x.IsCategory);
DiscordChannel category = categories.FirstOrDefault(x => x.Name.StartsWith(command.RawArgumentString.Trim(), StringComparison.OrdinalIgnoreCase)); DiscordChannel category = categories.FirstOrDefault(x => x.Name.StartsWith(command.RawArgumentString.Trim(), StringComparison.OrdinalIgnoreCase));
if (category == null) if (category == null)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Could not find a category by that name." Description = "Error: Could not find a category by that name."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (command.Channel.Id == category.Id) if (command.Channel.Id == category.Id)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: The ticket is already in that category." Description = "Error: The ticket is already in that category."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
try try
{ {
await command.Channel.ModifyAsync(modifiedAttributes => modifiedAttributes.Parent = category); await command.Channel.ModifyAsync(modifiedAttributes => modifiedAttributes.Parent = category);
} }
catch (UnauthorizedException) catch (UnauthorizedException)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Not authorized to move this ticket to that category." Description = "Error: Not authorized to move this ticket to that category."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordEmbed feedback = new DiscordEmbedBuilder DiscordEmbed feedback = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket was moved to " + category.Mention Description = "Ticket was moved to " + category.Mention
}; };
await command.RespondAsync(feedback); await command.RespondAsync(feedback);
} }
} }
} }

View file

@ -9,142 +9,142 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class NewCommand : BaseCommandModule public class NewCommand : BaseCommandModule
{ {
[Command("new")] [Command("new")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "new")) if (!Config.HasPermission(command.Member, "new"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the new command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the new command but did not have permission.");
return; return;
} }
// Check if user is blacklisted // Check if user is blacklisted
if (Database.IsBlacklisted(command.User.Id)) if (Database.IsBlacklisted(command.User.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You are banned from opening tickets." Description = "You are banned from opening tickets."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (Database.IsOpenTicket(command.Channel.Id)) if (Database.IsOpenTicket(command.Channel.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You cannot use this command in a ticket channel." Description = "You cannot use this command in a ticket channel."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordChannel category = command.Guild.GetChannel(Config.ticketCategory); DiscordChannel category = command.Guild.GetChannel(Config.ticketCategory);
DiscordChannel ticketChannel; DiscordChannel ticketChannel;
try try
{ {
ticketChannel = await command.Guild.CreateChannelAsync("ticket", ChannelType.Text, category); ticketChannel = await command.Guild.CreateChannelAsync("ticket", ChannelType.Text, category);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error occured while creating ticket, " + command.Member.Mention + Description = "Error occured while creating ticket, " + command.Member.Mention +
"!\nIs the channel limit reached in the server or ticket category?" "!\nIs the channel limit reached in the server or ticket category?"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (ticketChannel == null) if (ticketChannel == null)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error occured while creating ticket, " + command.Member.Mention + Description = "Error occured while creating ticket, " + command.Member.Mention +
"!\nIs the channel limit reached in the server or ticket category?" "!\nIs the channel limit reached in the server or ticket category?"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
ulong staffID = 0; ulong staffID = 0;
if (Config.randomAssignment) if (Config.randomAssignment)
{ {
staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0; staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0;
} }
long id = Database.NewTicket(command.Member.Id, staffID, ticketChannel.Id); long id = Database.NewTicket(command.Member.Id, staffID, ticketChannel.Id);
string ticketID = id.ToString("00000"); string ticketID = id.ToString("00000");
await ticketChannel.ModifyAsync(modifiedAttributes => modifiedAttributes.Name = "ticket-" + ticketID); await ticketChannel.ModifyAsync(modifiedAttributes => modifiedAttributes.Name = "ticket-" + ticketID);
await ticketChannel.AddOverwriteAsync(command.Member, Permissions.AccessChannels, Permissions.None); await ticketChannel.AddOverwriteAsync(command.Member, Permissions.AccessChannels, Permissions.None);
await ticketChannel.SendMessageAsync("Hello, " + command.Member.Mention + "!\n" + Config.welcomeMessage); await ticketChannel.SendMessageAsync("Hello, " + command.Member.Mention + "!\n" + Config.welcomeMessage);
// Refreshes the channel as changes were made to it above // Refreshes the channel as changes were made to it above
ticketChannel = command.Guild.GetChannel(ticketChannel.Id); ticketChannel = command.Guild.GetChannel(ticketChannel.Id);
if (staffID != 0) if (staffID != 0)
{ {
DiscordEmbed assignmentMessage = new DiscordEmbedBuilder DiscordEmbed assignmentMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket was randomly assigned to <@" + staffID + ">." Description = "Ticket was randomly assigned to <@" + staffID + ">."
}; };
await ticketChannel.SendMessageAsync(assignmentMessage); await ticketChannel.SendMessageAsync(assignmentMessage);
if (Config.assignmentNotifications) if (Config.assignmentNotifications)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "You have been randomly assigned to a newly opened support ticket: " + Description = "You have been randomly assigned to a newly opened support ticket: " +
ticketChannel.Mention ticketChannel.Mention
}; };
try try
{ {
DiscordMember staffMember = await command.Guild.GetMemberAsync(staffID); DiscordMember staffMember = await command.Guild.GetMemberAsync(staffID);
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
catch (NotFoundException) { } catch (NotFoundException) {}
catch (UnauthorizedException) { } catch (UnauthorizedException) {}
} }
} }
DiscordEmbed response = new DiscordEmbedBuilder DiscordEmbed response = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket opened, " + command.Member.Mention + "!\n" + ticketChannel.Mention Description = "Ticket opened, " + command.Member.Mention + "!\n" + ticketChannel.Mention
}; };
await command.RespondAsync(response); await command.RespondAsync(response);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket " + ticketChannel.Mention + " opened by " + command.Member.Mention + ".\n", Description = "Ticket " + ticketChannel.Mention + " opened by " + command.Member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = "Ticket " + ticketID } Footer = new DiscordEmbedBuilder.EmbedFooter {Text = "Ticket " + ticketID}
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }

View file

@ -10,173 +10,173 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class RandomAssignCommand : BaseCommandModule public class RandomAssignCommand : BaseCommandModule
{ {
[Command("rassign")] [Command("rassign")]
[Description("Randomly assigns a staff member to a ticket.")] [Description("Randomly assigns a staff member to a ticket.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArguments) public async Task OnExecute(CommandContext command, [RemainingText] string commandArguments)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "rassign")) if (!Config.HasPermission(command.Member, "rassign"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the rassign command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the rassign command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
// Get a random staff member who is verified to have the correct role if applicable // Get a random staff member who is verified to have the correct role if applicable
DiscordMember staffMember = await GetRandomVerifiedStaffMember(command, ticket); DiscordMember staffMember = await GetRandomVerifiedStaffMember(command, ticket);
if (staffMember == null) if (staffMember == null)
{ {
return; return;
} }
// Attempt to assign the staff member to the ticket // Attempt to assign the staff member to the ticket
if (!Database.AssignStaff(ticket, staffMember.Id)) if (!Database.AssignStaff(ticket, staffMember.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Failed to assign " + staffMember.Mention + " to ticket." Description = "Error: Failed to assign " + staffMember.Mention + " to ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
// Respond that the command was successful // Respond that the command was successful
DiscordEmbed feedback = new DiscordEmbedBuilder DiscordEmbed feedback = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Randomly assigned " + staffMember.Mention + " to ticket." Description = "Randomly assigned " + staffMember.Mention + " to ticket."
}; };
await command.RespondAsync(feedback); await command.RespondAsync(feedback);
// Send a notification to the staff member if applicable // Send a notification to the staff member if applicable
if (Config.assignmentNotifications) if (Config.assignmentNotifications)
{ {
try try
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "You have been randomly assigned to a support ticket: " + command.Channel.Mention Description = "You have been randomly assigned to a support ticket: " + command.Channel.Mention
}; };
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
catch (UnauthorizedException) { } catch (UnauthorizedException) {}
} }
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "." Description = staffMember.Mention + " was assigned to " + command.Channel.Mention + " by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
private async Task<DiscordMember> GetRandomVerifiedStaffMember(CommandContext command, Database.Ticket ticket) private async Task<DiscordMember> GetRandomVerifiedStaffMember(CommandContext command, Database.Ticket ticket)
{ {
if (command.RawArguments.Any()) // An argument was provided, check if this can be parsed into a role if (command.RawArguments.Any()) // An argument was provided, check if this can be parsed into a role
{ {
ulong roleID = 0; ulong roleID = 0;
// Try to parse either discord mention or ID // Try to parse either discord mention or ID
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!ulong.TryParse(parsedMessage[0], out roleID)) if (!ulong.TryParse(parsedMessage[0], out roleID))
{ {
// Try to find role by name // Try to find role by name
roleID = Utilities.GetRoleByName(command.Guild, command.RawArgumentString)?.Id ?? 0; roleID = Utilities.GetRoleByName(command.Guild, command.RawArgumentString)?.Id ?? 0;
} }
// Check if a role was found // Check if a role was found
if (roleID == 0) if (roleID == 0)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Could not find a role by that name/ID." Description = "Could not find a role by that name/ID."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return null; return null;
} }
// Check if role rassign should override staff's active status // Check if role rassign should override staff's active status
List<Database.StaffMember> staffMembers = Config.randomAssignRoleOverride List<Database.StaffMember> staffMembers = Config.randomAssignRoleOverride
? Database.GetAllStaff(ticket.assignedStaffID) ? Database.GetAllStaff(ticket.assignedStaffID)
: Database.GetActiveStaff(ticket.assignedStaffID); : Database.GetActiveStaff(ticket.assignedStaffID);
// Randomize the list before checking for roles in order to reduce number of API calls // Randomize the list before checking for roles in order to reduce number of API calls
staffMembers = Utilities.RandomizeList(staffMembers); staffMembers = Utilities.RandomizeList(staffMembers);
// Get the first staff member that has the role // Get the first staff member that has the role
foreach (Database.StaffMember sm in staffMembers) foreach (Database.StaffMember sm in staffMembers)
{ {
try try
{ {
DiscordMember verifiedMember = await command.Guild.GetMemberAsync(sm.userID); DiscordMember verifiedMember = await command.Guild.GetMemberAsync(sm.userID);
if (verifiedMember?.Roles?.Any(role => role.Id == roleID) ?? false) if (verifiedMember?.Roles?.Any(role => role.Id == roleID) ?? false)
{ {
return verifiedMember; return verifiedMember;
} }
} }
catch (Exception e) catch (Exception e)
{ {
command.Client.Logger.Log(LogLevel.Information, e, "Error occured trying to find a staff member in the rassign command."); command.Client.Logger.Log(LogLevel.Information, e, "Error occured trying to find a staff member in the rassign command.");
} }
} }
} }
else // No role was specified, any active staff will be picked else // No role was specified, any active staff will be picked
{ {
Database.StaffMember staffEntry = Database.GetRandomActiveStaff(ticket.assignedStaffID); Database.StaffMember staffEntry = Database.GetRandomActiveStaff(ticket.assignedStaffID);
if (staffEntry == null) if (staffEntry == null)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: There are no other staff members to choose from." Description = "Error: There are no other staff members to choose from."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return null; return null;
} }
// Get the staff member from discord // Get the staff member from discord
try try
{ {
return await command.Guild.GetMemberAsync(staffEntry.userID); return await command.Guild.GetMemberAsync(staffEntry.userID);
} }
catch (NotFoundException) { } catch (NotFoundException) { }
} }
// Send a more generic error if we get to this point and still haven't found the staff member // Send a more generic error if we get to this point and still haven't found the staff member
DiscordEmbed err = new DiscordEmbedBuilder DiscordEmbed err = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Could not find an applicable staff member." Description = "Error: Could not find an applicable staff member."
}; };
await command.RespondAsync(err); await command.RespondAsync(err);
return null; return null;
} }
} }
} }

View file

@ -35,4 +35,4 @@ namespace SupportChild.Commands
SupportChild.instance.Reload(); SupportChild.instance.Reload();
} }
} }
} }

View file

@ -40,7 +40,7 @@ namespace SupportChild.Commands
return; return;
} }
if (Database.RemoveMessage(identifier)) if(Database.RemoveMessage(identifier))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
@ -63,4 +63,4 @@ namespace SupportChild.Commands
} }
} }
} }

View file

@ -9,96 +9,96 @@ using MySql.Data.MySqlClient;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class RemoveStaffCommand : BaseCommandModule public class RemoveStaffCommand : BaseCommandModule
{ {
[Command("removestaff")] [Command("removestaff")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "removestaff")) if (!Config.HasPermission(command.Member, "removestaff"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the removestaff command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the removestaff command but did not have permission.");
return; return;
} }
ulong userID; ulong userID;
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedMessage.Any()) if (!parsedMessage.Any())
{ {
userID = command.Member.Id; userID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedMessage[0], out userID)) else if (!ulong.TryParse(parsedMessage[0], out userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
try try
{ {
await command.Client.GetUserAsync(userID); await command.Client.GetUserAsync(userID);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not find user on Discord)" Description = "Invalid ID/Mention. (Could not find user on Discord)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
if (!Database.IsStaff(userID)) if (!Database.IsStaff(userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "User is already not registered as staff." Description = "User is already not registered as staff."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
using (MySqlConnection c = Database.GetConnection()) using (MySqlConnection c = Database.GetConnection())
{ {
c.Open(); c.Open();
MySqlCommand deletion = new MySqlCommand(@"DELETE FROM staff WHERE user_id=@user_id", c); MySqlCommand deletion = new MySqlCommand(@"DELETE FROM staff WHERE user_id=@user_id", c);
deletion.Parameters.AddWithValue("@user_id", userID); deletion.Parameters.AddWithValue("@user_id", userID);
deletion.Prepare(); deletion.Prepare();
deletion.ExecuteNonQuery(); deletion.ExecuteNonQuery();
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "User was removed from staff." Description = "User was removed from staff."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "User was removed from staff.\n", Description = "User was removed from staff.\n",
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }
} }

View file

@ -8,89 +8,89 @@ using System.Threading.Tasks;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class SayCommand : BaseCommandModule public class SayCommand : BaseCommandModule
{ {
[Command("say")] [Command("say")]
[Cooldown(1, 2, CooldownBucketType.Channel)] [Cooldown(1, 2, CooldownBucketType.Channel)]
[Description("Prints a message with information from staff.")] [Description("Prints a message with information from staff.")]
public async Task OnExecute(CommandContext command, string identifier) public async Task OnExecute(CommandContext command, string identifier)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "say")) if (!Config.HasPermission(command.Member, "say"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission.");
return; return;
} }
if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message message)) if (!Database.TryGetMessage(identifier.ToLower(), out Database.Message message))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "There is no message with that identifier." Description = "There is no message with that identifier."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordEmbed reply = new DiscordEmbedBuilder DiscordEmbed reply = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = message.message Description = message.message
}; };
await command.RespondAsync(reply); await command.RespondAsync(reply);
} }
[Command("say")] [Command("say")]
[Cooldown(1, 2.0, CooldownBucketType.Channel)] [Cooldown(1, 2.0, CooldownBucketType.Channel)]
[Description("Prints a list of staff messages.")] [Description("Prints a list of staff messages.")]
public async Task OnExecute(CommandContext command) public async Task OnExecute(CommandContext command)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "say")) if (!Config.HasPermission(command.Member, "say"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the say command but did not have permission.");
return; return;
} }
List<Database.Message> messages = Database.GetAllMessages(); List<Database.Message> messages = Database.GetAllMessages();
if (!messages.Any()) if (!messages.Any())
{ {
DiscordEmbed error = new DiscordEmbedBuilder() DiscordEmbed error = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("There are no messages registered."); .WithDescription("There are no messages registered.");
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
List<string> listItems = new List<string>(); List<string> listItems = new List<string>();
foreach (Database.Message message in messages) foreach (Database.Message message in messages)
{ {
listItems.Add("**" + message.identifier + "** Added by <@" + message.userID + ">\n"); listItems.Add("**" + message.identifier + "** Added by <@" + message.userID + ">\n");
} }
LinkedList<string> listMessages = Utilities.ParseListIntoMessages(listItems); LinkedList<string> listMessages = Utilities.ParseListIntoMessages(listItems);
foreach (string listMessage in listMessages) foreach (string listMessage in listMessages)
{ {
DiscordEmbed channelInfo = new DiscordEmbedBuilder() DiscordEmbed channelInfo = new DiscordEmbedBuilder()
.WithTitle("Available messages: ") .WithTitle("Available messages: ")
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription(listMessage); .WithDescription(listMessage);
await command.RespondAsync(channelInfo); await command.RespondAsync(channelInfo);
} }
} }
} }
} }

View file

@ -60,4 +60,4 @@ namespace SupportChild.Commands
} }
} }
} }
} }

View file

@ -8,91 +8,91 @@ using MySql.Data.MySqlClient;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class SetTicketCommand : BaseCommandModule public class SetTicketCommand :BaseCommandModule
{ {
[Command("setticket")] [Command("setticket")]
[Description("Turns a channel into a ticket, warning: this will let anyone with write access delete the channel using the close command.")] [Description("Turns a channel into a ticket, warning: this will let anyone with write access delete the channel using the close command.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
using (MySqlConnection c = Database.GetConnection()) using (MySqlConnection c = Database.GetConnection())
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "setticket")) if (!Config.HasPermission(command.Member, "setticket"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the setticket command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the setticket command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (Database.IsOpenTicket(command.Channel.Id)) if (Database.IsOpenTicket(command.Channel.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is already a ticket." Description = "This channel is already a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
ulong userID; ulong userID;
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedMessage.Any()) if (!parsedMessage.Any())
{ {
userID = command.Member.Id; userID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedMessage[0], out userID)) else if (!ulong.TryParse(parsedMessage[0], out userID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
DiscordUser user = await command.Client.GetUserAsync(userID); DiscordUser user = await command.Client.GetUserAsync(userID);
if (user == null) if (user == null)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention." Description = "Invalid ID/Mention."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
long id = Database.NewTicket(userID, 0, command.Channel.Id); long id = Database.NewTicket(userID, 0, command.Channel.Id);
string ticketID = id.ToString("00000"); string ticketID = id.ToString("00000");
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Channel has been designated ticket " + ticketID + "." Description = "Channel has been designated ticket " + ticketID + "."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = command.Channel.Mention + " has been designated ticket " + ticketID + " by " + command.Member.Mention + "." Description = command.Channel.Mention + " has been designated ticket " + ticketID + " by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }
} }

View file

@ -38,4 +38,4 @@ namespace SupportChild.Commands
await command.RespondAsync(botInfo); await command.RespondAsync(botInfo);
} }
} }
} }

View file

@ -48,4 +48,4 @@ namespace SupportChild.Commands
} }
} }
} }
} }

View file

@ -8,71 +8,71 @@ using MySql.Data.MySqlClient;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class ToggleActiveCommand : BaseCommandModule public class ToggleActiveCommand : BaseCommandModule
{ {
[Command("toggleactive")] [Command("toggleactive")]
[Aliases("ta")] [Aliases("ta")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
using (MySqlConnection c = Database.GetConnection()) using (MySqlConnection c = Database.GetConnection())
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "toggleactive")) if (!Config.HasPermission(command.Member, "toggleactive"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the toggleactive command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the toggleactive command but did not have permission.");
return; return;
} }
ulong staffID; ulong staffID;
string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString); string[] parsedMessage = Utilities.ParseIDs(command.RawArgumentString);
if (!parsedMessage.Any()) if (!parsedMessage.Any())
{ {
staffID = command.Member.Id; staffID = command.Member.Id;
} }
else if (!ulong.TryParse(parsedMessage[0], out staffID)) else if (!ulong.TryParse(parsedMessage[0], out staffID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)" Description = "Invalid ID/Mention. (Could not convert to numerical)"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetStaff(staffID, out Database.StaffMember staffMember)) if (!Database.TryGetStaff(staffID, out Database.StaffMember staffMember))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You have not been registered as staff." Description = "You have not been registered as staff."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
c.Open(); c.Open();
MySqlCommand update = new MySqlCommand(@"UPDATE staff SET active = @active WHERE user_id = @user_id", c); MySqlCommand update = new MySqlCommand(@"UPDATE staff SET active = @active WHERE user_id = @user_id", c);
update.Parameters.AddWithValue("@user_id", staffID); update.Parameters.AddWithValue("@user_id", staffID);
update.Parameters.AddWithValue("@active", !staffMember.active); update.Parameters.AddWithValue("@active", !staffMember.active);
update.Prepare(); update.Prepare();
update.ExecuteNonQuery(); update.ExecuteNonQuery();
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, 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." Description = staffMember.active ? "Staff member is now set as inactive and will no longer be randomly assigned any support tickets." : "Staff member is now set as active and will be randomly assigned support tickets again."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
} }
} }
} }
} }

View file

@ -10,163 +10,163 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class TranscriptCommand : BaseCommandModule public class TranscriptCommand : BaseCommandModule
{ {
[Command("transcript")] [Command("transcript")]
[Cooldown(1, 5, CooldownBucketType.User)] [Cooldown(1, 5, CooldownBucketType.User)]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "transcript")) if (!Config.HasPermission(command.Member, "transcript"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the transcript command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the transcript command but did not have permission.");
return; return;
} }
Database.Ticket ticket; Database.Ticket ticket;
string strippedMessage = command.Message.Content.Replace(Config.prefix, ""); string strippedMessage = command.Message.Content.Replace(Config.prefix, "");
string[] parsedMessage = strippedMessage.Replace("<@!", "").Replace("<@", "").Replace(">", "").Split(); string[] parsedMessage = strippedMessage.Replace("<@!", "").Replace("<@", "").Replace(">", "").Split();
// If there are no arguments use current channel // If there are no arguments use current channel
if (parsedMessage.Length < 2) if (parsedMessage.Length < 2)
{ {
if (Database.TryGetOpenTicket(command.Channel.Id, out ticket)) if (Database.TryGetOpenTicket(command.Channel.Id, out ticket))
{ {
try try
{ {
await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "ERROR: Could not save transcript file. Aborting..." Description = "ERROR: Could not save transcript file. Aborting..."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
throw; throw;
} }
} }
else else
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
} }
else else
{ {
// Check if argument is numerical, if not abort // Check if argument is numerical, if not abort
if (!uint.TryParse(parsedMessage[1], out uint ticketID)) if (!uint.TryParse(parsedMessage[1], out uint ticketID))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Argument must be a number." Description = "Argument must be a number."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
// If the ticket is still open, generate a new fresh transcript // If the ticket is still open, generate a new fresh transcript
if (Database.TryGetOpenTicketByID(ticketID, out ticket) && ticket?.creatorID == command.Member.Id) if (Database.TryGetOpenTicketByID(ticketID, out ticket) && ticket?.creatorID == command.Member.Id)
{ {
try try
{ {
await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id); await Transcriber.ExecuteAsync(command.Channel.Id, ticket.id);
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "ERROR: Could not save transcript file. Aborting..." Description = "ERROR: Could not save transcript file. Aborting..."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
throw; throw;
} }
} }
// If there is no open or closed ticket, send an error. If there is a closed ticket we will simply use the old transcript from when the ticket was closed. // If there is no open or closed ticket, send an error. If there is a closed ticket we will simply use the old transcript from when the ticket was closed.
else if (!Database.TryGetClosedTicket(ticketID, out ticket) || ticket?.creatorID != command.Member.Id && !Database.IsStaff(command.Member.Id)) else if (!Database.TryGetClosedTicket(ticketID, out ticket) || (ticket?.creatorID != command.Member.Id && !Database.IsStaff(command.Member.Id)))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Could not find a closed ticket with that number which you opened." + (Config.HasPermission(command.Member, "list") ? "\n(Use the " + Config.prefix + "list command to see all your tickets)" : "") Description = "Could not find a closed ticket with that number which you opened." + (Config.HasPermission(command.Member, "list") ? "\n(Use the " + Config.prefix + "list command to see all your tickets)" : "")
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
} }
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed embed = new DiscordEmbedBuilder DiscordEmbed embed = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
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 }
}; };
using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) 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.WithFiles(new Dictionary<string, Stream>() { { Transcriber.GetFilename(ticket.id), file } });
await logChannel.SendMessageAsync(message); await logChannel.SendMessageAsync(message);
} }
} }
try try
{ {
// Send transcript privately // Send transcript privately
DiscordEmbed directMessageEmbed = new DiscordEmbedBuilder DiscordEmbed directMessageEmbed = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Transcript generated, " + command.Member.Mention + "!\n" Description = "Transcript generated, " + command.Member.Mention + "!\n"
}; };
using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read)) using (FileStream file = new FileStream(Transcriber.GetPath(ticket.id), FileMode.Open, FileAccess.Read))
{ {
DiscordMessageBuilder directMessage = new DiscordMessageBuilder(); DiscordMessageBuilder directMessage = new DiscordMessageBuilder();
directMessage.WithEmbed(directMessageEmbed); directMessage.WithEmbed(directMessageEmbed);
directMessage.WithFiles(new Dictionary<string, Stream>() { { Transcriber.GetFilename(ticket.id), file } }); directMessage.WithFiles(new Dictionary<string, Stream>() { { Transcriber.GetFilename(ticket.id), file } });
await command.Member.SendMessageAsync(directMessage); await command.Member.SendMessageAsync(directMessage);
} }
// Respond to message directly // Respond to message directly
DiscordEmbed response = new DiscordEmbedBuilder DiscordEmbed response = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Transcript sent, " + command.Member.Mention + "!\n" Description = "Transcript sent, " + command.Member.Mention + "!\n"
}; };
await command.RespondAsync(response); await command.RespondAsync(response);
} }
catch (UnauthorizedException) catch (UnauthorizedException)
{ {
// Send transcript privately // Send transcript privately
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Not allowed to send direct message to you, " + command.Member.Mention + ", please check your privacy settings.\n" Description = "Not allowed to send direct message to you, " + command.Member.Mention + ", please check your privacy settings.\n"
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
} }
} }
} }
} }

View file

@ -0,0 +1,71 @@
using System.Threading.Tasks;
using DSharpPlus.CommandsNext;
using DSharpPlus.CommandsNext.Attributes;
using DSharpPlus.Entities;
using Microsoft.Extensions.Logging;
namespace SupportChild.Commands
{
public class UnassignCommand : BaseCommandModule
{
[Command("unassign")]
[Description("Unassigns a staff member from a ticket.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{
// Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "unassign"))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "You do not have permission to use this command."
};
await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the unassign command but did not have permission.");
return;
}
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
};
await command.RespondAsync(error);
return;
}
if (!Database.UnassignStaff(ticket))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed to unassign staff from ticket."
};
await command.RespondAsync(error);
return;
}
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Unassigned staff from ticket."
};
await command.RespondAsync(message);
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Staff was unassigned from " + command.Channel.Mention + " by " + command.Member.Mention + "."
};
await logChannel.SendMessageAsync(logMessage);
}
}
}
}

View file

@ -1,71 +0,0 @@
using System.Threading.Tasks;
using DSharpPlus.CommandsNext;
using DSharpPlus.CommandsNext.Attributes;
using DSharpPlus.Entities;
using Microsoft.Extensions.Logging;
namespace SupportChild.Commands
{
public class UnassignCommand : BaseCommandModule
{
[Command("unassign")]
[Description("Unassigns a staff member from a ticket.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{
// Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "unassign"))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "You do not have permission to use this command."
};
await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the unassign command but did not have permission.");
return;
}
// Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
};
await command.RespondAsync(error);
return;
}
if (!Database.UnassignStaff(ticket))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Error: Failed to unassign staff from ticket."
};
await command.RespondAsync(error);
return;
}
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Unassigned staff from ticket."
};
await command.RespondAsync(message);
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Staff was unassigned from " + command.Channel.Mention + " by " + command.Member.Mention + "."
};
await logChannel.SendMessageAsync(logMessage);
}
}
}
}

View file

@ -8,92 +8,92 @@ using Microsoft.Extensions.Logging;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class UnblacklistCommand : BaseCommandModule public class UnblacklistCommand : BaseCommandModule
{ {
[Command("unblacklist")] [Command("unblacklist")]
[Description("Un-blacklists a user from opening tickets.")] [Description("Un-blacklists a user from opening tickets.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "unblacklist")) if (!Config.HasPermission(command.Member, "unblacklist"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the unblacklist command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the unblacklist command but did not have permission.");
return; return;
} }
string[] words = Utilities.ParseIDs(command.RawArgumentString); string[] words = Utilities.ParseIDs(command.RawArgumentString);
foreach (string word in words) foreach (string word in words)
{ {
if (ulong.TryParse(word, out ulong userId)) if (ulong.TryParse(word, out ulong userId))
{ {
DiscordUser blacklistedUser = null; DiscordUser blacklistedUser = null;
try try
{ {
blacklistedUser = await command.Client.GetUserAsync(userId); blacklistedUser = await command.Client.GetUserAsync(userId);
} }
catch (NotFoundException) { } catch (NotFoundException) { }
if (blacklistedUser == null) if (blacklistedUser == null)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error: Could not find user." Description = "Error: Could not find user."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
continue; continue;
} }
try try
{ {
if (!Database.Unblacklist(blacklistedUser.Id)) if (!Database.Unblacklist(blacklistedUser.Id))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = blacklistedUser.Mention + " is not blacklisted." Description = blacklistedUser.Mention + " is not blacklisted."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
continue; continue;
} }
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Removed " + blacklistedUser.Mention + " from blacklist." Description = "Removed " + blacklistedUser.Mention + " from blacklist."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = blacklistedUser.Mention + " was unblacklisted from opening tickets by " + command.Member.Mention + "." Description = blacklistedUser.Mention + " was unblacklisted from opening tickets by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
catch (Exception) catch (Exception)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "Error occured while removing " + blacklistedUser.Mention + " from blacklist." Description = "Error occured while removing " + blacklistedUser.Mention + " from blacklist."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
throw; throw;
} }
} }
} }
} }
} }
} }

View file

@ -7,64 +7,64 @@ using MySql.Data.MySqlClient;
namespace SupportChild.Commands namespace SupportChild.Commands
{ {
public class UnsetTicketCommand : BaseCommandModule public class UnsetTicketCommand : BaseCommandModule
{ {
[Command("unsetticket")] [Command("unsetticket")]
[Description( [Description(
"Deletes a channel from the ticket system without deleting the channel.")] "Deletes a channel from the ticket system without deleting the channel.")]
public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs) public async Task OnExecute(CommandContext command, [RemainingText] string commandArgs)
{ {
using (MySqlConnection c = Database.GetConnection()) using (MySqlConnection c = Database.GetConnection())
{ {
// Check if the user has permission to use this command. // Check if the user has permission to use this command.
if (!Config.HasPermission(command.Member, "unsetticket")) if (!Config.HasPermission(command.Member, "unsetticket"))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "You do not have permission to use this command." Description = "You do not have permission to use this command."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
command.Client.Logger.Log(LogLevel.Information, "User tried to use the unsetticket command but did not have permission."); command.Client.Logger.Log(LogLevel.Information, "User tried to use the unsetticket command but did not have permission.");
return; return;
} }
// Check if ticket exists in the database // Check if ticket exists in the database
if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket)) if (!Database.TryGetOpenTicket(command.Channel.Id, out Database.Ticket ticket))
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = "This channel is not a ticket." Description = "This channel is not a ticket."
}; };
await command.RespondAsync(error); await command.RespondAsync(error);
return; return;
} }
c.Open(); c.Open();
MySqlCommand deletion = new MySqlCommand(@"DELETE FROM tickets WHERE channel_id=@channel_id", c); MySqlCommand deletion = new MySqlCommand(@"DELETE FROM tickets WHERE channel_id=@channel_id", c);
deletion.Parameters.AddWithValue("@channel_id", command.Channel.Id); deletion.Parameters.AddWithValue("@channel_id", command.Channel.Id);
deletion.Prepare(); deletion.Prepare();
deletion.ExecuteNonQuery(); deletion.ExecuteNonQuery();
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Channel has been undesignated as a ticket." Description = "Channel has been undesignated as a ticket."
}; };
await command.RespondAsync(message); await command.RespondAsync(message);
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel); DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = command.Channel.Mention + " has been undesignated as a ticket by " + command.Member.Mention + "." Description = command.Channel.Mention + " has been undesignated as a ticket by " + command.Member.Mention + "."
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
} }
} }
} }

View file

@ -10,134 +10,134 @@ using YamlDotNet.Serialization;
namespace SupportChild namespace SupportChild
{ {
internal static class Config internal static class Config
{ {
internal static string token = ""; internal static string token = "";
internal static string prefix = ""; internal static string prefix = "";
internal static ulong logChannel; internal static ulong logChannel;
internal static ulong ticketCategory; internal static ulong ticketCategory;
internal static ulong reactionMessage; internal static ulong reactionMessage;
internal static string welcomeMessage = ""; internal static string welcomeMessage = "";
internal static string logLevel = "Information"; internal static string logLevel = "Information";
internal static string timestampFormat = "yyyy-MMM-dd HH:mm"; internal static string timestampFormat = "yyyy-MMM-dd HH:mm";
internal static bool randomAssignment = false; internal static bool randomAssignment = false;
internal static bool randomAssignRoleOverride = false; // TODO: Implement internal static bool randomAssignRoleOverride = false;
internal static string presenceType = "Playing"; internal static string presenceType = "Playing";
internal static string presenceText = ""; internal static string presenceText = "";
internal static bool ticketUpdatedNotifications = false; internal static bool ticketUpdatedNotifications = false;
internal static double ticketUpdatedNotificationDelay = 0.0; internal static double ticketUpdatedNotificationDelay = 0.0;
internal static bool assignmentNotifications = false; internal static bool assignmentNotifications = false;
internal static bool closingNotifications = false; internal static bool closingNotifications = false;
internal static string hostName = "127.0.0.1"; internal static string hostName = "127.0.0.1";
internal static int port = 3306; internal static int port = 3306;
internal static string database = "supportbot"; internal static string database = "supportbot";
internal static string username = "supportbot"; internal static string username = "supportbot";
internal static string password = ""; internal static string password = "";
private static readonly Dictionary<string, ulong[]> permissions = new Dictionary<string, ulong[]> private static readonly Dictionary<string, ulong[]> permissions = new Dictionary<string, ulong[]>
{ {
// Public commands // Public commands
{ "close", new ulong[]{ } }, { "close", new ulong[]{ } },
{ "list", new ulong[]{ } }, { "list", new ulong[]{ } },
{ "new", new ulong[]{ } }, { "new", new ulong[]{ } },
{ "say", new ulong[]{ } }, { "say", new ulong[]{ } },
{ "status", new ulong[]{ } }, { "status", new ulong[]{ } },
{ "summary", new ulong[]{ } }, { "summary", new ulong[]{ } },
{ "transcript", new ulong[]{ } }, { "transcript", new ulong[]{ } },
// Moderator commands // Moderator commands
{ "add", new ulong[]{ } }, { "add", new ulong[]{ } },
{ "addmessage", new ulong[]{ } }, { "addmessage", new ulong[]{ } },
{ "assign", new ulong[]{ } }, { "assign", new ulong[]{ } },
{ "blacklist", new ulong[]{ } }, { "blacklist", new ulong[]{ } },
{ "listassigned", new ulong[]{ } }, { "listassigned", new ulong[]{ } },
{ "listoldest", new ulong[]{ } }, { "listoldest", new ulong[]{ } },
{ "listunassigned", new ulong[]{ } }, { "listunassigned", new ulong[]{ } },
{ "move", new ulong[]{ } }, { "move", new ulong[]{ } },
{ "rassign", new ulong[]{ } }, { "rassign", new ulong[]{ } },
{ "removemessage", new ulong[]{ } }, { "removemessage", new ulong[]{ } },
{ "setsummary", new ulong[]{ } }, { "setsummary", new ulong[]{ } },
{ "toggleactive", new ulong[]{ } }, { "toggleactive", new ulong[]{ } },
{ "unassign", new ulong[]{ } }, { "unassign", new ulong[]{ } },
{ "unblacklist", new ulong[]{ } }, { "unblacklist", new ulong[]{ } },
// Admin commands // Admin commands
{ "addstaff", new ulong[]{ } }, { "addstaff", new ulong[]{ } },
{ "reload", new ulong[]{ } }, { "reload", new ulong[]{ } },
{ "removestaff", new ulong[]{ } }, { "removestaff", new ulong[]{ } },
{ "setticket", new ulong[]{ } }, { "setticket", new ulong[]{ } },
{ "unsetticket", new ulong[]{ } }, { "unsetticket", new ulong[]{ } },
}; };
public static void LoadConfig()
{
// Writes default config to file if it does not already exist
if (!File.Exists("./config.yml"))
{
File.WriteAllText("./config.yml", Encoding.UTF8.GetString(Resources.default_config));
}
public static void LoadConfig() // Reads config contents into FileStream
{ FileStream stream = File.OpenRead("./config.yml");
// Writes default config to file if it does not already exist
if (!File.Exists("./config.yml"))
{
File.WriteAllText("./config.yml", Encoding.UTF8.GetString(Resources.default_config));
}
// Reads config contents into FileStream // Converts the FileStream into a YAML object
FileStream stream = File.OpenRead("./config.yml"); IDeserializer deserializer = new DeserializerBuilder().Build();
object yamlObject = deserializer.Deserialize(new StreamReader(stream));
// Converts the FileStream into a YAML object // Converts the YAML object into a JSON object as the YAML ones do not support traversal or selection of nodes by name
IDeserializer deserializer = new DeserializerBuilder().Build(); ISerializer serializer = new SerializerBuilder().JsonCompatible().Build();
object yamlObject = deserializer.Deserialize(new StreamReader(stream)); JObject json = JObject.Parse(serializer.Serialize(yamlObject));
// Converts the YAML object into a JSON object as the YAML ones do not support traversal or selection of nodes by name // Sets up the bot
ISerializer serializer = new SerializerBuilder().JsonCompatible().Build(); token = json.SelectToken("bot.token").Value<string>() ?? "";
JObject json = JObject.Parse(serializer.Serialize(yamlObject)); prefix = json.SelectToken("bot.prefix").Value<string>() ?? "";
logChannel = json.SelectToken("bot.log-channel").Value<ulong>();
ticketCategory = json.SelectToken("bot.ticket-category")?.Value<ulong>() ?? 0;
reactionMessage = json.SelectToken("bot.reaction-message")?.Value<ulong>() ?? 0;
welcomeMessage = json.SelectToken("bot.welcome-message").Value<string>() ?? "";
logLevel = json.SelectToken("bot.console-log-level").Value<string>() ?? "";
timestampFormat = json.SelectToken("bot.timestamp-format").Value<string>() ?? "yyyy-MM-dd HH:mm";
randomAssignment = json.SelectToken("bot.random-assignment")?.Value<bool>() ?? false;
randomAssignRoleOverride = json.SelectToken("bot.random-assign-role-override")?.Value<bool>() ?? false;
presenceType = json.SelectToken("bot.presence-type")?.Value<string>() ?? "Playing";
presenceText = json.SelectToken("bot.presence-text")?.Value<string>() ?? "";
// Sets up the bot ticketUpdatedNotifications = json.SelectToken("notifications.ticket-updated")?.Value<bool>() ?? false;
token = json.SelectToken("bot.token").Value<string>() ?? ""; ticketUpdatedNotificationDelay = json.SelectToken("notifications.ticket-updated-delay")?.Value<double>() ?? 0.0;
prefix = json.SelectToken("bot.prefix").Value<string>() ?? ""; assignmentNotifications = json.SelectToken("notifications.assignment")?.Value<bool>() ?? false;
logChannel = json.SelectToken("bot.log-channel").Value<ulong>(); closingNotifications = json.SelectToken("notifications.closing")?.Value<bool>() ?? false;
ticketCategory = json.SelectToken("bot.ticket-category")?.Value<ulong>() ?? 0;
reactionMessage = json.SelectToken("bot.reaction-message")?.Value<ulong>() ?? 0;
welcomeMessage = json.SelectToken("bot.welcome-message").Value<string>() ?? "";
logLevel = json.SelectToken("bot.console-log-level").Value<string>() ?? "";
timestampFormat = json.SelectToken("bot.timestamp-format").Value<string>() ?? "yyyy-MM-dd HH:mm";
randomAssignment = json.SelectToken("bot.random-assignment")?.Value<bool>() ?? false;
randomAssignRoleOverride = json.SelectToken("bot.random-assign-role-override")?.Value<bool>() ?? false;
presenceType = json.SelectToken("bot.presence-type")?.Value<string>() ?? "Playing";
presenceText = json.SelectToken("bot.presence-text")?.Value<string>() ?? "";
ticketUpdatedNotifications = json.SelectToken("notifications.ticket-updated")?.Value<bool>() ?? false; // Reads database info
ticketUpdatedNotificationDelay = json.SelectToken("notifications.ticket-updated-delay")?.Value<double>() ?? 0.0; hostName = json.SelectToken("database.address")?.Value<string>() ?? "";
assignmentNotifications = json.SelectToken("notifications.assignment")?.Value<bool>() ?? false; port = json.SelectToken("database.port")?.Value<int>() ?? 3306;
closingNotifications = json.SelectToken("notifications.closing")?.Value<bool>() ?? false; database = json.SelectToken("database.name")?.Value<string>() ?? "supportchild";
username = json.SelectToken("database.user")?.Value<string>() ?? "supportchild";
password = json.SelectToken("database.password")?.Value<string>() ?? "";
// Reads database info timestampFormat = timestampFormat.Trim();
hostName = json.SelectToken("database.address")?.Value<string>() ?? "";
port = json.SelectToken("database.port")?.Value<int>() ?? 3306;
database = json.SelectToken("database.name")?.Value<string>() ?? "supportbot";
username = json.SelectToken("database.user")?.Value<string>() ?? "supportbot";
password = json.SelectToken("database.password")?.Value<string>() ?? "";
timestampFormat = timestampFormat.Trim(); foreach (KeyValuePair<string, ulong[]> node in permissions.ToList())
{
try
{
permissions[node.Key] = json.SelectToken("permissions." + node.Key).Value<JArray>().Values<ulong>().ToArray();
}
catch (ArgumentNullException)
{
Console.WriteLine("Permission node '" + node.Key + "' was not found in the config, using default value: []");
}
}
}
foreach (KeyValuePair<string, ulong[]> node in permissions.ToList()) /// <summary>
{ /// Checks whether a user has a specific permission.
try /// </summary>
{ /// <param name="member">The Discord user to check.</param>
permissions[node.Key] = json.SelectToken("permissions." + node.Key).Value<JArray>().Values<ulong>().ToArray(); /// <param name="permission">The permission name to check.</param>
} /// <returns></returns>
catch (ArgumentNullException) public static bool HasPermission(DiscordMember member, string permission)
{ {
Console.WriteLine("Permission node '" + node.Key + "' was not found in the config, using default value: []"); return member.Roles.Any(role => permissions[permission].Contains(role.Id)) || permissions[permission].Contains(member.Guild.Id);
} }
} }
} }
/// <summary>
/// Checks whether a user has a specific permission.
/// </summary>
/// <param name="member">The Discord user to check.</param>
/// <param name="permission">The permission name to check.</param>
/// <returns></returns>
public static bool HasPermission(DiscordMember member, string permission)
{
return member.Roles.Any(role => permissions[permission].Contains(role.Id)) || permissions[permission].Contains(member.Guild.Id);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -12,296 +12,296 @@ using Microsoft.Extensions.Logging;
namespace SupportChild namespace SupportChild
{ {
internal class EventHandler internal class EventHandler
{ {
private DiscordClient discordClient; private DiscordClient discordClient;
//DateTime for the end of the cooldown //DateTime for the end of the cooldown
private static Dictionary<ulong, DateTime> reactionTicketCooldowns = new Dictionary<ulong, DateTime>(); private static Dictionary<ulong, DateTime> reactionTicketCooldowns = new Dictionary<ulong, DateTime>();
public EventHandler(DiscordClient client) public EventHandler(DiscordClient client)
{ {
discordClient = client; this.discordClient = client;
} }
internal Task OnReady(DiscordClient client, ReadyEventArgs e) internal Task OnReady(DiscordClient client, ReadyEventArgs e)
{ {
discordClient.Logger.Log(LogLevel.Information, "Client is ready to process events."); discordClient.Logger.Log(LogLevel.Information, "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))
{ {
Console.WriteLine("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead."); Console.WriteLine("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead.");
activityType = ActivityType.Playing; activityType = ActivityType.Playing;
} }
discordClient.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online); this.discordClient.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online);
return Task.CompletedTask; return Task.CompletedTask;
} }
internal Task OnGuildAvailable(DiscordClient client, GuildCreateEventArgs e) internal Task OnGuildAvailable(DiscordClient client, GuildCreateEventArgs e)
{ {
discordClient.Logger.Log(LogLevel.Information, $"Guild available: {e.Guild.Name}"); discordClient.Logger.Log(LogLevel.Information, $"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)
{ {
discordClient.Logger.Log(LogLevel.Information, role.Name.PadRight(40, '.') + roleID); discordClient.Logger.Log(LogLevel.Information, role.Name.PadRight(40, '.') + roleID);
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
internal Task OnClientError(DiscordClient client, ClientErrorEventArgs e) internal Task OnClientError(DiscordClient client, ClientErrorEventArgs e)
{ {
discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}"); discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}");
return Task.CompletedTask; return Task.CompletedTask;
} }
internal async Task OnMessageCreated(DiscordClient client, MessageCreateEventArgs e) internal 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
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = 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
}; };
DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID); DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID);
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
catch (NotFoundException) { } catch (NotFoundException) { }
catch (UnauthorizedException) { } catch (UnauthorizedException) { }
} }
} }
internal Task OnCommandError(CommandsNextExtension commandSystem, CommandErrorEventArgs e) internal Task OnCommandError(CommandsNextExtension commandSystem, CommandErrorEventArgs e)
{ {
switch (e.Exception) switch (e.Exception)
{ {
case CommandNotFoundException _: case CommandNotFoundException _:
return Task.CompletedTask; return Task.CompletedTask;
case ChecksFailedException _: case ChecksFailedException _:
{ {
foreach (CheckBaseAttribute attr in ((ChecksFailedException)e.Exception).FailedChecks) foreach (CheckBaseAttribute attr in ((ChecksFailedException)e.Exception).FailedChecks)
{ {
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Red, Color = DiscordColor.Red,
Description = ParseFailedCheck(attr) Description = this.ParseFailedCheck(attr)
}; };
e.Context?.Channel?.SendMessageAsync(error); e.Context?.Channel?.SendMessageAsync(error);
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
default: default:
{ {
discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}"); discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}");
DiscordEmbed error = new DiscordEmbedBuilder DiscordEmbed error = 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."
}; };
e.Context?.Channel?.SendMessageAsync(error); e.Context?.Channel?.SendMessageAsync(error);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }
} }
internal async Task OnReactionAdded(DiscordClient client, MessageReactionAddEventArgs e) internal async Task OnReactionAdded(DiscordClient client, MessageReactionAddEventArgs e)
{ {
if (e.Message.Id != Config.reactionMessage) return; if (e.Message.Id != Config.reactionMessage) return;
DiscordGuild guild = e.Message.Channel.Guild; DiscordGuild guild = e.Message.Channel.Guild;
DiscordMember member = await guild.GetMemberAsync(e.User.Id); DiscordMember member = await guild.GetMemberAsync(e.User.Id);
if (!Config.HasPermission(member, "new") || Database.IsBlacklisted(member.Id)) return; if (!Config.HasPermission(member, "new") || Database.IsBlacklisted(member.Id)) return;
if (reactionTicketCooldowns.ContainsKey(member.Id)) if (reactionTicketCooldowns.ContainsKey(member.Id))
{ {
if (reactionTicketCooldowns[member.Id] > DateTime.Now) return; // cooldown has not expired if (reactionTicketCooldowns[member.Id] > DateTime.Now) return; // cooldown has not expired
else reactionTicketCooldowns.Remove(member.Id); // cooldown exists but has expired, delete it else reactionTicketCooldowns.Remove(member.Id); // cooldown exists but has expired, delete it
} }
DiscordChannel category = guild.GetChannel(Config.ticketCategory); DiscordChannel category = guild.GetChannel(Config.ticketCategory);
DiscordChannel ticketChannel = await guild.CreateChannelAsync("ticket", ChannelType.Text, category); DiscordChannel ticketChannel = await guild.CreateChannelAsync("ticket", ChannelType.Text, category);
if (ticketChannel == null) return; if (ticketChannel == null) return;
ulong staffID = 0; ulong staffID = 0;
if (Config.randomAssignment) if (Config.randomAssignment)
{ {
staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0; staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0;
} }
long id = Database.NewTicket(member.Id, staffID, ticketChannel.Id); long id = Database.NewTicket(member.Id, staffID, ticketChannel.Id);
reactionTicketCooldowns.Add(member.Id, DateTime.Now.AddSeconds(10)); // add a cooldown which expires in 10 seconds reactionTicketCooldowns.Add(member.Id, DateTime.Now.AddSeconds(10)); // add a cooldown which expires in 10 seconds
string ticketID = id.ToString("00000"); string ticketID = id.ToString("00000");
await ticketChannel.ModifyAsync(model => model.Name = "ticket-" + ticketID); await ticketChannel.ModifyAsync(model => model.Name = "ticket-" + ticketID);
await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels, Permissions.None); await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels, Permissions.None);
await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage); await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage);
// Remove user's reaction // Remove user's reaction
await e.Message.DeleteReactionAsync(e.Emoji, e.User); await e.Message.DeleteReactionAsync(e.Emoji, e.User);
// Refreshes the channel as changes were made to it above // Refreshes the channel as changes were made to it above
ticketChannel = await SupportChild.GetClient().GetChannelAsync(ticketChannel.Id); ticketChannel = await SupportChild.GetClient().GetChannelAsync(ticketChannel.Id);
if (staffID != 0) if (staffID != 0)
{ {
DiscordEmbed assignmentMessage = new DiscordEmbedBuilder DiscordEmbed assignmentMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket was randomly assigned to <@" + staffID + ">." Description = "Ticket was randomly assigned to <@" + staffID + ">."
}; };
await ticketChannel.SendMessageAsync(assignmentMessage); await ticketChannel.SendMessageAsync(assignmentMessage);
if (Config.assignmentNotifications) if (Config.assignmentNotifications)
{ {
DiscordEmbed message = new DiscordEmbedBuilder DiscordEmbed message = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "You have been randomly assigned to a newly opened support ticket: " + Description = "You have been randomly assigned to a newly opened support ticket: " +
ticketChannel.Mention ticketChannel.Mention
}; };
try try
{ {
DiscordMember staffMember = await guild.GetMemberAsync(staffID); DiscordMember staffMember = await guild.GetMemberAsync(staffID);
await staffMember.SendMessageAsync(message); await staffMember.SendMessageAsync(message);
} }
catch (NotFoundException) catch (NotFoundException)
{ {
} }
catch (UnauthorizedException) catch (UnauthorizedException)
{ {
} }
} }
} }
// Log it if the log channel exists // Log it if the log channel exists
DiscordChannel logChannel = guild.GetChannel(Config.logChannel); DiscordChannel logChannel = guild.GetChannel(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
DiscordEmbed logMessage = new DiscordEmbedBuilder DiscordEmbed logMessage = new DiscordEmbedBuilder
{ {
Color = DiscordColor.Green, Color = DiscordColor.Green,
Description = "Ticket " + ticketChannel.Mention + " opened by " + member.Mention + ".\n", Description = "Ticket " + ticketChannel.Mention + " opened by " + member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = "Ticket " + ticketID } Footer = new DiscordEmbedBuilder.EmbedFooter {Text = "Ticket " + ticketID}
}; };
await logChannel.SendMessageAsync(logMessage); await logChannel.SendMessageAsync(logMessage);
} }
} }
internal async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e) internal 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.AddOverwriteAsync(e.Member, Permissions.AccessChannels, Permissions.None); await channel.AddOverwriteAsync(e.Member, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder() DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Green) .WithColor(DiscordColor.Green)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket."); .WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket.");
await channel.SendMessageAsync(message); await channel.SendMessageAsync(message);
} }
} }
catch (Exception) { } catch (Exception) { }
} }
} }
internal async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e) internal async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e)
{ {
if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets)) if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{ {
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)
{ {
DiscordEmbed message = new DiscordEmbedBuilder() DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server."); .WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server.");
await channel.SendMessageAsync(message); await channel.SendMessageAsync(message);
} }
} }
catch (Exception) { } catch (Exception) { }
} }
} }
if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0) if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0)
{ {
DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel); DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel);
if (logChannel != null) if (logChannel != null)
{ {
foreach (Database.Ticket ticket in assignedTickets) 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)
{ {
DiscordEmbed message = new DiscordEmbedBuilder() DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red) .WithColor(DiscordColor.Red)
.WithDescription("Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">"); .WithDescription("Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">");
await logChannel.SendMessageAsync(message); await logChannel.SendMessageAsync(message);
} }
} }
catch (Exception) { } catch (Exception) { }
} }
} }
} }
} }
private string ParseFailedCheck(CheckBaseAttribute attr) private string ParseFailedCheck(CheckBaseAttribute attr)
{ {
switch (attr) switch (attr)
{ {
case CooldownAttribute _: case CooldownAttribute _:
return "You cannot use do that so often!"; return "You cannot use do that so often!";
case RequireOwnerAttribute _: case RequireOwnerAttribute _:
return "Only the server owner can use that command!"; return "Only the server owner can use that command!";
case RequirePermissionsAttribute _: case RequirePermissionsAttribute _:
return "You don't have permission to do that!"; return "You don't have permission to do that!";
case RequireRolesAttribute _: case RequireRolesAttribute _:
return "You do not have a required role!"; return "You do not have a required role!";
case RequireUserPermissionsAttribute _: case RequireUserPermissionsAttribute _:
return "You don't have permission to do that!"; return "You don't have permission to do that!";
case RequireNsfwAttribute _: case RequireNsfwAttribute _:
return "This command can only be used in an NSFW channel!"; return "This command can only be used in an NSFW channel!";
default: default:
return "Unknown Discord API error occured, please try again later."; return "Unknown Discord API error occured, please try again later.";
} }
} }
} }
} }

View file

@ -1,124 +1,124 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value> <value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="default_config" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\default_config.yml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="default_config" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\default_config.yml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root> </root>

View file

@ -25,7 +25,7 @@ namespace SupportChild
private async Task MainAsync() private async Task MainAsync()
{ {
instance = this; instance = this;
Console.WriteLine("Starting SupportChild version " + GetVersion() + "..."); Console.WriteLine("Starting SupportChild version " + GetVersion() + "...");
try try
{ {
@ -61,10 +61,10 @@ namespace SupportChild
this.discordClient.Dispose(); this.discordClient.Dispose();
Console.WriteLine("Discord client disconnected."); Console.WriteLine("Discord client disconnected.");
} }
Console.WriteLine("Loading config \"" + Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "config.yml\""); Console.WriteLine("Loading config \"" + Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "config.yml\"");
Config.LoadConfig(); Config.LoadConfig();
// Check if token is unset // Check if token is unset
if (Config.token == "<add-token-here>" || Config.token == "") if (Config.token == "<add-token-here>" || Config.token == "")
{ {
@ -84,16 +84,16 @@ namespace SupportChild
Console.WriteLine("Could not set up database tables, please confirm connection settings, status of the server and permissions of MySQL user. Error: " + e); Console.WriteLine("Could not set up database tables, please confirm connection settings, status of the server and permissions of MySQL user. Error: " + e);
throw; throw;
} }
Console.WriteLine("Setting up Discord client..."); Console.WriteLine("Setting up Discord client...");
// Checking log level // Checking log level
if (!Enum.TryParse(Config.logLevel, true, out LogLevel logLevel)) if (!Enum.TryParse(Config.logLevel, true, out LogLevel logLevel))
{ {
Console.WriteLine("Log level '" + Config.logLevel + "' invalid, using 'Information' instead."); Console.WriteLine("Log level '" + Config.logLevel + "' invalid, using 'Information' instead.");
logLevel = LogLevel.Information; logLevel = LogLevel.Information;
} }
// Setting up client configuration // Setting up client configuration
DiscordConfiguration cfg = new DiscordConfiguration DiscordConfiguration cfg = new DiscordConfiguration
{ {
@ -103,11 +103,11 @@ namespace SupportChild
AutoReconnect = true, AutoReconnect = true,
Intents = DiscordIntents.All Intents = DiscordIntents.All
}; };
this.discordClient = new DiscordClient(cfg); this.discordClient = new DiscordClient(cfg);
this.eventHandler = new EventHandler(this.discordClient); this.eventHandler = new EventHandler(this.discordClient);
Console.WriteLine("Hooking events..."); Console.WriteLine("Hooking events...");
this.discordClient.Ready += this.eventHandler.OnReady; this.discordClient.Ready += this.eventHandler.OnReady;
this.discordClient.GuildAvailable += this.eventHandler.OnGuildAvailable; this.discordClient.GuildAvailable += this.eventHandler.OnGuildAvailable;
@ -119,11 +119,11 @@ namespace SupportChild
{ {
this.discordClient.MessageReactionAdded += this.eventHandler.OnReactionAdded; this.discordClient.MessageReactionAdded += this.eventHandler.OnReactionAdded;
} }
Console.WriteLine("Registering commands..."); Console.WriteLine("Registering commands...");
commands = discordClient.UseCommandsNext(new CommandsNextConfiguration commands = discordClient.UseCommandsNext(new CommandsNextConfiguration
{ {
StringPrefixes = new[] { Config.prefix } StringPrefixes = new []{ Config.prefix }
}); });
this.commands.RegisterCommands<AddCommand>(); this.commands.RegisterCommands<AddCommand>();
@ -160,4 +160,4 @@ namespace SupportChild
await this.discordClient.ConnectAsync(); await this.discordClient.ConnectAsync();
} }
} }
} }

View file

@ -1,70 +1,70 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<ApplicationIcon>ellie_icon.ico</ApplicationIcon>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<Version>1.2.0</Version>
<StartupObject>SupportChild.SupportChild</StartupObject>
<Authors>EmotionChild</Authors>
<Product />
<PackageProjectUrl>https://github.com/EmotionChild/SupportChild</PackageProjectUrl>
<RepositoryUrl>https://github.com/EmotionChild/SupportChild</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageIconUrl>https://cdn.emotionchild.com/Ellie.png</PackageIconUrl>
<Description>A Discord support bot build for the Ellie's Home Discord server</Description>
<AssemblyVersion>2.6.1.1</AssemblyVersion>
<FileVersion>2.6.1.1</FileVersion>
<NeutralLanguage>en</NeutralLanguage>
<PackageVersion>1.2.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DSharpPlus" Version="4.2.0-nightly-01109" />
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.2.0-nightly-01109" />
<PackageReference Include="DSharpPlus.Interactivity" Version="4.2.0-nightly-01109" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="MiniRazor.CodeGen" Version="2.2.1" />
<PackageReference Include="MySql.Data" Version="8.0.28" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="Tyrrrz.Extensions" Version="1.6.5" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup> <PropertyGroup>
<None Include="..\LICENSE"> <OutputType>Exe</OutputType>
<Pack>True</Pack> <ApplicationIcon>ellie_icon.ico</ApplicationIcon>
<PackagePath></PackagePath> <TargetFramework>net6.0</TargetFramework>
</None> <RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
</ItemGroup> <Version>1.2.0</Version>
<StartupObject>SupportChild.SupportChild</StartupObject>
<Authors>EmotionChild</Authors>
<Product />
<PackageProjectUrl>https://github.com/EmotionChild/SupportChild</PackageProjectUrl>
<RepositoryUrl>https://github.com/EmotionChild/SupportChild</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageIconUrl>https://cdn.emotionchild.com/Ellie.png</PackageIconUrl>
<Description>A Discord support bot build for the Ellie's Home Discord server</Description>
<AssemblyVersion>2.6.1.1</AssemblyVersion>
<FileVersion>2.6.1.1</FileVersion>
<NeutralLanguage>en</NeutralLanguage>
<PackageVersion>1.2.0</PackageVersion>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="lib\" /> <PackageReference Include="DSharpPlus" Version="4.2.0" />
</ItemGroup> <PackageReference Include="DSharpPlus.CommandsNext" Version="4.2.0" />
<PackageReference Include="DSharpPlus.Interactivity" Version="4.2.0" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="MiniRazor.CodeGen" Version="2.2.1" />
<PackageReference Include="MySql.Data" Version="8.0.29" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Superpower" Version="3.0.0" />
<PackageReference Include="Tyrrrz.Extensions" Version="1.6.5" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="DiscordChatExporter.Core"> <Compile Update="Properties\Resources.Designer.cs">
<HintPath>lib\DiscordChatExporter.Core.dll</HintPath> <DesignTime>True</DesignTime>
</Reference> <AutoGen>True</AutoGen>
</ItemGroup> <DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="lib\" />
</ItemGroup>
<ItemGroup>
<Reference Include="DiscordChatExporter.Core">
<HintPath>lib\DiscordChatExporter.Core.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

View file

@ -59,4 +59,4 @@ namespace SupportChild
return "ticket-" + ticketNumber.ToString("00000") + ".html"; return "ticket-" + ticketNumber.ToString("00000") + ".html";
} }
} }
} }

View file

@ -15,8 +15,8 @@ namespace SupportChild
{ {
byte[] box = new byte[1]; byte[] box = new byte[1];
do provider.GetBytes(box); do provider.GetBytes(box);
while (!(box[0] < n * (byte.MaxValue / n))); while (!(box[0] < n * (Byte.MaxValue / n)));
int k = box[0] % n; int k = (box[0] % n);
n--; n--;
T value = list[k]; T value = list[k];
list[k] = list[n]; list[k] = list[n];
@ -32,11 +32,11 @@ namespace SupportChild
{ {
return new string[0]; return new string[0];
} }
return args.Trim().Replace("<@!", "").Replace("<@", "").Replace(">", "").Split(); return args.Trim().Replace("<@!", "").Replace("<@", "").Replace(">", "").Split();
} }
public static LinkedList<string> ParseListIntoMessages(List<string> listItems) public static LinkedList<string> ParseListIntoMessages(List<string> listItems)
{ {
LinkedList<string> messages = new LinkedList<string>(); LinkedList<string> messages = new LinkedList<string>();
foreach (string listItem in listItems) foreach (string listItem in listItems)
@ -68,4 +68,4 @@ namespace SupportChild
return null; return null;
} }
} }
} }

View file

@ -1,84 +1,84 @@
bot: bot:
# Bot token. # Bot token.
token: "<add-token-here>" token: "<add-token-here>"
# Command prefix. # Command prefix.
prefix: "-" prefix: "-"
# Channel where ticket logs are posted (recommended) # Channel where ticket logs are posted (recommended)
log-channel: 000000000000000000 log-channel: 000000000000000000
# Category where the ticket will be created, it will have the same permissions of that ticket plus read permissions for the user opening the ticket (recommended) # Category where the ticket will be created, it will have the same permissions of that ticket plus read permissions for the user opening the ticket (recommended)
ticket-category: 000000000000000000 ticket-category: 000000000000000000
# A message which will open new tickets when users react to it (optional) # A message which will open new tickets when users react to it (optional)
reaction-message: 000000000000000000 reaction-message: 000000000000000000
# Message posted when a ticket is opened. # Message posted when a ticket is opened.
welcome-message: "Please describe your issue below, and include all information needed for us to help you." welcome-message: "Please describe your issue below, and include all information needed for us to help you."
# Decides what messages are shown in console # Decides what messages are shown in console
# Possible values are: Critical, Error, Warning, Information, Debug. # Possible values are: Critical, Error, Warning, Information, Debug.
console-log-level: "Information" console-log-level: "Information"
# Format for timestamps in transcripts and google sheets if used # Format for timestamps in transcripts and google sheets if used
timestamp-format: "yyyy-MM-dd HH:mm" timestamp-format: "yyyy-MM-dd HH:mm"
# Whether or not staff members should be randomly assigned tickets when they are made. Individual staff members can opt out using the toggleactive command. # Whether or not staff members should be randomly assigned tickets when they are made. Individual staff members can opt out using the toggleactive command.
random-assignment: true random-assignment: true
# If set to true the rasssign command will include staff members set as inactive if a specific role is specified in the command. # If set to true the rasssign command will include staff members set as inactive if a specific role is specified in the command.
# This can be useful if you have admins set as inactive to not automatically recieve tickets and then have moderators elevate tickets when needed. # This can be useful if you have admins set as inactive to not automatically recieve tickets and then have moderators elevate tickets when needed.
random-assign-role-override: true random-assign-role-override: true
# Sets the type of activity for the bot to display in its presence status # Sets the type of activity for the bot to display in its presence status
# Possible values are: Playing, Streaming, ListeningTo, Watching, Competing # Possible values are: Playing, Streaming, ListeningTo, Watching, Competing
presence-type: "ListeningTo" presence-type: "ListeningTo"
# Sets the activity text shown in the bot's status # Sets the activity text shown in the bot's status
presence-text: "-new" presence-text: "-new"
notifications: notifications:
# Notifies the assigned staff member when a new message is posted in a ticket if the ticket has been silent for a configurable amount of time # Notifies the assigned staff member when a new message is posted in a ticket if the ticket has been silent for a configurable amount of time
# Other staff members and bots do not trigger this. # Other staff members and bots do not trigger this.
ticket-updated: true ticket-updated: true
# The above notification will only be sent if the ticket has been silent for more than this amount of days. Default is 0.5 days. # The above notification will only be sent if the ticket has been silent for more than this amount of days. Default is 0.5 days.
ticket-updated-delay: 0.5 ticket-updated-delay: 0.5
# Notifies staff when they are assigned to tickets # Notifies staff when they are assigned to tickets
assignment: true assignment: true
# Notifies the user opening the ticket that their ticket was closed and includes the transcript # Notifies the user opening the ticket that their ticket was closed and includes the transcript
closing: true closing: true
database: database:
# Address and port of the mysql server # Address and port of the mysql server
address: "127.0.0.1" address: "127.0.0.1"
port: 3306 port: 3306
# Name of the database to use # Name of the database to use
name: "supportbot" name: "supportchild"
# Username and password for authentication # Username and password for authentication
user: "" user: ""
password: "" password: ""
# Set up which roles are allowed to use different commands. # Set up which roles are allowed to use different commands.
# Example: # Example:
# new: [ 000000000000000000, 111111111111111111 ] # new: [ 000000000000000000, 111111111111111111 ]
# They are grouped into suggested command groups below for first time setup. # They are grouped into suggested command groups below for first time setup.
permissions: permissions:
# Public commands # Public commands
close: [] close: []
list: [] list: []
new: [] new: []
say: [] say: []
status: [] status: []
summary: [] summary: []
transcript: [] transcript: []
# Moderator commands # Moderator commands
add: [] add: []
addmessage: [] addmessage: []
assign: [] assign: []
blacklist: [] blacklist: []
listassigned: [] listassigned: []
listoldest: [] listoldest: []
listunassigned: [] listunassigned: []
move: [] move: []
rassign: [] rassign: []
removemessage: [] removemessage: []
setsummary: [] setsummary: []
toggleactive: [] toggleactive: []
unassign: [] unassign: []
unblacklist: [] unblacklist: []
# Admin commands # Admin commands
addstaff: [] addstaff: []
reload: [] reload: []
removestaff: [] removestaff: []
setticket: [] setticket: []
unsetticket: [] unsetticket: []