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.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
@ -12,7 +12,7 @@ updates:
open-pull-requests-limit: 5
reviewers:
- EmotionChild
target-branch: "main"
target-branch: "development"
labels:
- "nuget"
- "dependencies"
- "dependencies"

View file

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

3
.gitignore vendored
View file

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

View file

@ -1 +1,3 @@
# 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
# Visual Studio Version 17
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}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SupportChild", "SupportChild\SupportChild.csproj", "{B043AACB-D763-4C61-9524-C8B7C58DA3EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -11,15 +8,9 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9124DF58-D261-4906-8ECA-D853DEBE07D4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B2CD3447-A8BA-4B02-9E08-A75CBBD2BDCB}
{B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B043AACB-D763-4C61-9524-C8B7C58DA3EF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
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
{
public class AddCommand : BaseCommandModule
{
[Command("add")]
[Description("Adds a user to 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, "add"))
{
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 add command but did not have permission.");
return;
}
public class AddCommand : BaseCommandModule
{
[Command("add")]
[Description("Adds a user to 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, "add"))
{
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 add command but did not have permission.");
return;
}
// Check if ticket exists in the database
if (!Database.IsOpenTicket(command.Channel.Id))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
};
await command.RespondAsync(error);
return;
}
// Check if ticket exists in the database
if (!Database.IsOpenTicket(command.Channel.Id))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "This channel is not a ticket."
};
await command.RespondAsync(error);
return;
}
string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString);
foreach (string parsedArg in parsedArgs)
{
if (!ulong.TryParse(parsedArg, out ulong userID))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)"
};
await command.RespondAsync(error);
continue;
}
string[] parsedArgs = Utilities.ParseIDs(command.RawArgumentString);
foreach (string parsedArg in parsedArgs)
{
if (!ulong.TryParse(parsedArg, out ulong userID))
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not convert to numerical)"
};
await command.RespondAsync(error);
continue;
}
DiscordMember mentionedMember;
try
{
mentionedMember = await command.Guild.GetMemberAsync(userID);
}
catch (Exception)
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not find user on this server)"
};
await command.RespondAsync(error);
continue;
}
DiscordMember mentionedMember;
try
{
mentionedMember = await command.Guild.GetMemberAsync(userID);
}
catch (Exception)
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Invalid ID/Mention. (Could not find user on this server)"
};
await command.RespondAsync(error);
continue;
}
try
{
await command.Channel.AddOverwriteAsync(mentionedMember, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Added " + mentionedMember.Mention + " to ticket."
};
await command.RespondAsync(message);
try
{
await command.Channel.AddOverwriteAsync(mentionedMember, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Added " + mentionedMember.Mention + " to ticket."
};
await command.RespondAsync(message);
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = mentionedMember.Mention + " was added to " + command.Channel.Mention +
" by " + command.Member.Mention + "."
};
await logChannel.SendMessageAsync(logMessage);
}
}
catch (Exception)
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not add <@" + parsedArg + "> to ticket, unknown error occured."
};
await command.RespondAsync(message);
}
}
}
}
}
// Log it if the log channel exists
DiscordChannel logChannel = command.Guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = mentionedMember.Mention + " was added to " + command.Channel.Mention +
" by " + command.Member.Mention + "."
};
await logChannel.SendMessageAsync(logMessage);
}
}
catch (Exception)
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Could not add <@" + parsedArg + "> to ticket, unknown error occured."
};
await command.RespondAsync(message);
}
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

@ -10,134 +10,134 @@ using YamlDotNet.Serialization;
namespace SupportChild
{
internal static class Config
{
internal static string token = "";
internal static string prefix = "";
internal static ulong logChannel;
internal static ulong ticketCategory;
internal static ulong reactionMessage;
internal static string welcomeMessage = "";
internal static string logLevel = "Information";
internal static string timestampFormat = "yyyy-MMM-dd HH:mm";
internal static bool randomAssignment = false;
internal static bool randomAssignRoleOverride = false; // TODO: Implement
internal static string presenceType = "Playing";
internal static string presenceText = "";
internal static class Config
{
internal static string token = "";
internal static string prefix = "";
internal static ulong logChannel;
internal static ulong ticketCategory;
internal static ulong reactionMessage;
internal static string welcomeMessage = "";
internal static string logLevel = "Information";
internal static string timestampFormat = "yyyy-MMM-dd HH:mm";
internal static bool randomAssignment = false;
internal static bool randomAssignRoleOverride = false;
internal static string presenceType = "Playing";
internal static string presenceText = "";
internal static bool ticketUpdatedNotifications = false;
internal static double ticketUpdatedNotificationDelay = 0.0;
internal static bool assignmentNotifications = false;
internal static bool closingNotifications = false;
internal static bool ticketUpdatedNotifications = false;
internal static double ticketUpdatedNotificationDelay = 0.0;
internal static bool assignmentNotifications = false;
internal static bool closingNotifications = false;
internal static string hostName = "127.0.0.1";
internal static int port = 3306;
internal static string database = "supportbot";
internal static string username = "supportbot";
internal static string password = "";
internal static string hostName = "127.0.0.1";
internal static int port = 3306;
internal static string database = "supportbot";
internal static string username = "supportbot";
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
{ "close", new ulong[]{ } },
{ "list", new ulong[]{ } },
{ "new", new ulong[]{ } },
{ "say", new ulong[]{ } },
{ "status", new ulong[]{ } },
{ "summary", new ulong[]{ } },
{ "transcript", new ulong[]{ } },
{ "close", new ulong[]{ } },
{ "list", new ulong[]{ } },
{ "new", new ulong[]{ } },
{ "say", new ulong[]{ } },
{ "status", new ulong[]{ } },
{ "summary", new ulong[]{ } },
{ "transcript", new ulong[]{ } },
// Moderator commands
{ "add", new ulong[]{ } },
{ "addmessage", new ulong[]{ } },
{ "assign", new ulong[]{ } },
{ "blacklist", new ulong[]{ } },
{ "listassigned", new ulong[]{ } },
{ "listoldest", new ulong[]{ } },
{ "listunassigned", new ulong[]{ } },
{ "move", new ulong[]{ } },
{ "rassign", new ulong[]{ } },
{ "removemessage", new ulong[]{ } },
{ "setsummary", new ulong[]{ } },
{ "toggleactive", new ulong[]{ } },
{ "unassign", new ulong[]{ } },
{ "unblacklist", new ulong[]{ } },
{ "add", new ulong[]{ } },
{ "addmessage", new ulong[]{ } },
{ "assign", new ulong[]{ } },
{ "blacklist", new ulong[]{ } },
{ "listassigned", new ulong[]{ } },
{ "listoldest", new ulong[]{ } },
{ "listunassigned", new ulong[]{ } },
{ "move", new ulong[]{ } },
{ "rassign", new ulong[]{ } },
{ "removemessage", new ulong[]{ } },
{ "setsummary", new ulong[]{ } },
{ "toggleactive", new ulong[]{ } },
{ "unassign", new ulong[]{ } },
{ "unblacklist", new ulong[]{ } },
// Admin commands
{ "addstaff", new ulong[]{ } },
{ "reload", new ulong[]{ } },
{ "removestaff", new ulong[]{ } },
{ "setticket", new ulong[]{ } },
{ "unsetticket", new ulong[]{ } },
};
{ "addstaff", new ulong[]{ } },
{ "reload", new ulong[]{ } },
{ "removestaff", new ulong[]{ } },
{ "setticket", 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()
{
// 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
FileStream stream = File.OpenRead("./config.yml");
// Reads config contents into FileStream
FileStream stream = File.OpenRead("./config.yml");
// Converts the FileStream into a YAML object
IDeserializer deserializer = new DeserializerBuilder().Build();
object yamlObject = deserializer.Deserialize(new StreamReader(stream));
// Converts the FileStream into a YAML object
IDeserializer deserializer = new DeserializerBuilder().Build();
object yamlObject = deserializer.Deserialize(new StreamReader(stream));
// Converts the YAML object into a JSON object as the YAML ones do not support traversal or selection of nodes by name
ISerializer serializer = new SerializerBuilder().JsonCompatible().Build();
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
ISerializer serializer = new SerializerBuilder().JsonCompatible().Build();
JObject json = JObject.Parse(serializer.Serialize(yamlObject));
// Sets up the bot
token = json.SelectToken("bot.token").Value<string>() ?? "";
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
token = json.SelectToken("bot.token").Value<string>() ?? "";
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>() ?? "";
ticketUpdatedNotifications = json.SelectToken("notifications.ticket-updated")?.Value<bool>() ?? false;
ticketUpdatedNotificationDelay = json.SelectToken("notifications.ticket-updated-delay")?.Value<double>() ?? 0.0;
assignmentNotifications = json.SelectToken("notifications.assignment")?.Value<bool>() ?? false;
closingNotifications = json.SelectToken("notifications.closing")?.Value<bool>() ?? false;
ticketUpdatedNotifications = json.SelectToken("notifications.ticket-updated")?.Value<bool>() ?? false;
ticketUpdatedNotificationDelay = json.SelectToken("notifications.ticket-updated-delay")?.Value<double>() ?? 0.0;
assignmentNotifications = json.SelectToken("notifications.assignment")?.Value<bool>() ?? false;
closingNotifications = json.SelectToken("notifications.closing")?.Value<bool>() ?? false;
// Reads database info
hostName = json.SelectToken("database.address")?.Value<string>() ?? "";
port = json.SelectToken("database.port")?.Value<int>() ?? 3306;
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
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();
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())
{
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: []");
}
}
}
/// <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);
}
}
}
/// <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
{
internal class EventHandler
{
private DiscordClient discordClient;
internal class EventHandler
{
private DiscordClient discordClient;
//DateTime for the end of the cooldown
private static Dictionary<ulong, DateTime> reactionTicketCooldowns = new Dictionary<ulong, DateTime>();
//DateTime for the end of the cooldown
private static Dictionary<ulong, DateTime> reactionTicketCooldowns = new Dictionary<ulong, DateTime>();
public EventHandler(DiscordClient client)
{
discordClient = client;
}
public EventHandler(DiscordClient client)
{
this.discordClient = client;
}
internal Task OnReady(DiscordClient client, ReadyEventArgs e)
{
discordClient.Logger.Log(LogLevel.Information, "Client is ready to process events.");
internal Task OnReady(DiscordClient client, ReadyEventArgs e)
{
discordClient.Logger.Log(LogLevel.Information, "Client is ready to process events.");
// Checking activity type
if (!Enum.TryParse(Config.presenceType, true, out ActivityType activityType))
{
Console.WriteLine("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead.");
activityType = ActivityType.Playing;
}
// Checking activity type
if (!Enum.TryParse(Config.presenceType, true, out ActivityType activityType))
{
Console.WriteLine("Presence type '" + Config.presenceType + "' invalid, using 'Playing' instead.");
activityType = ActivityType.Playing;
}
discordClient.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online);
return Task.CompletedTask;
}
this.discordClient.UpdateStatusAsync(new DiscordActivity(Config.presenceText, activityType), UserStatus.Online);
return Task.CompletedTask;
}
internal Task OnGuildAvailable(DiscordClient client, GuildCreateEventArgs e)
{
discordClient.Logger.Log(LogLevel.Information, $"Guild available: {e.Guild.Name}");
internal Task OnGuildAvailable(DiscordClient client, GuildCreateEventArgs e)
{
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)
{
discordClient.Logger.Log(LogLevel.Information, role.Name.PadRight(40, '.') + roleID);
}
return Task.CompletedTask;
}
foreach ((ulong roleID, DiscordRole role) in roles)
{
discordClient.Logger.Log(LogLevel.Information, role.Name.PadRight(40, '.') + roleID);
}
return Task.CompletedTask;
}
internal Task OnClientError(DiscordClient client, ClientErrorEventArgs e)
{
discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}");
internal Task OnClientError(DiscordClient client, ClientErrorEventArgs e)
{
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)
{
if (e.Author.IsBot)
{
return;
}
internal async Task OnMessageCreated(DiscordClient client, MessageCreateEventArgs e)
{
if (e.Author.IsBot)
{
return;
}
// Check if ticket exists in the database and ticket notifications are enabled
if (!Database.TryGetOpenTicket(e.Channel.Id, out Database.Ticket ticket) || !Config.ticketUpdatedNotifications)
{
return;
}
// Check if ticket exists in the database and ticket notifications are enabled
if (!Database.TryGetOpenTicket(e.Channel.Id, out Database.Ticket ticket) || !Config.ticketUpdatedNotifications)
{
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
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))
{
try
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "A ticket you are assigned to has been updated: " + e.Channel.Mention
};
// Sends a DM to the assigned staff member if at least a day has gone by since the last message and the user sending the message isn't staff
IReadOnlyList<DiscordMessage> messages = await e.Channel.GetMessagesAsync(2);
if (messages.Count > 1 && messages[1].Timestamp < DateTimeOffset.UtcNow.AddDays(Config.ticketUpdatedNotificationDelay * -1) && !Database.IsStaff(e.Author.Id))
{
try
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "A ticket you are assigned to has been updated: " + e.Channel.Mention
};
DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID);
await staffMember.SendMessageAsync(message);
}
catch (NotFoundException) { }
catch (UnauthorizedException) { }
}
}
DiscordMember staffMember = await e.Guild.GetMemberAsync(ticket.assignedStaffID);
await staffMember.SendMessageAsync(message);
}
catch (NotFoundException) { }
catch (UnauthorizedException) { }
}
}
internal Task OnCommandError(CommandsNextExtension commandSystem, CommandErrorEventArgs e)
{
switch (e.Exception)
{
case CommandNotFoundException _:
return Task.CompletedTask;
case ChecksFailedException _:
{
foreach (CheckBaseAttribute attr in ((ChecksFailedException)e.Exception).FailedChecks)
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = ParseFailedCheck(attr)
};
e.Context?.Channel?.SendMessageAsync(error);
}
return Task.CompletedTask;
}
internal Task OnCommandError(CommandsNextExtension commandSystem, CommandErrorEventArgs e)
{
switch (e.Exception)
{
case CommandNotFoundException _:
return Task.CompletedTask;
case ChecksFailedException _:
{
foreach (CheckBaseAttribute attr in ((ChecksFailedException)e.Exception).FailedChecks)
{
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = this.ParseFailedCheck(attr)
};
e.Context?.Channel?.SendMessageAsync(error);
}
return Task.CompletedTask;
}
default:
{
discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}");
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Internal error occured, please report this to the developer."
};
e.Context?.Channel?.SendMessageAsync(error);
return Task.CompletedTask;
}
}
}
default:
{
discordClient.Logger.Log(LogLevel.Error, $"Exception occured: {e.Exception.GetType()}: {e.Exception}");
DiscordEmbed error = new DiscordEmbedBuilder
{
Color = DiscordColor.Red,
Description = "Internal error occured, please report this to the developer."
};
e.Context?.Channel?.SendMessageAsync(error);
return Task.CompletedTask;
}
}
}
internal async Task OnReactionAdded(DiscordClient client, MessageReactionAddEventArgs e)
{
if (e.Message.Id != Config.reactionMessage) return;
internal async Task OnReactionAdded(DiscordClient client, MessageReactionAddEventArgs e)
{
if (e.Message.Id != Config.reactionMessage) return;
DiscordGuild guild = e.Message.Channel.Guild;
DiscordMember member = await guild.GetMemberAsync(e.User.Id);
DiscordGuild guild = e.Message.Channel.Guild;
DiscordMember member = await guild.GetMemberAsync(e.User.Id);
if (!Config.HasPermission(member, "new") || Database.IsBlacklisted(member.Id)) return;
if (reactionTicketCooldowns.ContainsKey(member.Id))
{
if (reactionTicketCooldowns[member.Id] > DateTime.Now) return; // cooldown has not expired
else reactionTicketCooldowns.Remove(member.Id); // cooldown exists but has expired, delete it
}
if (!Config.HasPermission(member, "new") || Database.IsBlacklisted(member.Id)) return;
if (reactionTicketCooldowns.ContainsKey(member.Id))
{
if (reactionTicketCooldowns[member.Id] > DateTime.Now) return; // cooldown has not expired
else reactionTicketCooldowns.Remove(member.Id); // cooldown exists but has expired, delete it
}
DiscordChannel category = guild.GetChannel(Config.ticketCategory);
DiscordChannel ticketChannel = await guild.CreateChannelAsync("ticket", ChannelType.Text, category);
DiscordChannel category = guild.GetChannel(Config.ticketCategory);
DiscordChannel ticketChannel = await guild.CreateChannelAsync("ticket", ChannelType.Text, category);
if (ticketChannel == null) return;
if (ticketChannel == null) return;
ulong staffID = 0;
if (Config.randomAssignment)
{
staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0;
}
ulong staffID = 0;
if (Config.randomAssignment)
{
staffID = Database.GetRandomActiveStaff(0)?.userID ?? 0;
}
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
string ticketID = id.ToString("00000");
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
string ticketID = id.ToString("00000");
await ticketChannel.ModifyAsync(model => model.Name = "ticket-" + ticketID);
await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels, Permissions.None);
await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage);
await ticketChannel.ModifyAsync(model => model.Name = "ticket-" + ticketID);
await ticketChannel.AddOverwriteAsync(member, Permissions.AccessChannels, Permissions.None);
await ticketChannel.SendMessageAsync("Hello, " + member.Mention + "!\n" + Config.welcomeMessage);
// Remove user's reaction
await e.Message.DeleteReactionAsync(e.Emoji, e.User);
// Remove user's reaction
await e.Message.DeleteReactionAsync(e.Emoji, e.User);
// Refreshes the channel as changes were made to it above
ticketChannel = await SupportChild.GetClient().GetChannelAsync(ticketChannel.Id);
// Refreshes the channel as changes were made to it above
ticketChannel = await SupportChild.GetClient().GetChannelAsync(ticketChannel.Id);
if (staffID != 0)
{
DiscordEmbed assignmentMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Ticket was randomly assigned to <@" + staffID + ">."
};
await ticketChannel.SendMessageAsync(assignmentMessage);
if (staffID != 0)
{
DiscordEmbed assignmentMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Ticket was randomly assigned to <@" + staffID + ">."
};
await ticketChannel.SendMessageAsync(assignmentMessage);
if (Config.assignmentNotifications)
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "You have been randomly assigned to a newly opened support ticket: " +
ticketChannel.Mention
};
if (Config.assignmentNotifications)
{
DiscordEmbed message = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "You have been randomly assigned to a newly opened support ticket: " +
ticketChannel.Mention
};
try
{
DiscordMember staffMember = await guild.GetMemberAsync(staffID);
await staffMember.SendMessageAsync(message);
}
catch (NotFoundException)
{
}
catch (UnauthorizedException)
{
}
}
}
try
{
DiscordMember staffMember = await guild.GetMemberAsync(staffID);
await staffMember.SendMessageAsync(message);
}
catch (NotFoundException)
{
}
catch (UnauthorizedException)
{
}
}
}
// Log it if the log channel exists
DiscordChannel logChannel = guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Ticket " + ticketChannel.Mention + " opened by " + member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter { Text = "Ticket " + ticketID }
};
await logChannel.SendMessageAsync(logMessage);
}
}
// Log it if the log channel exists
DiscordChannel logChannel = guild.GetChannel(Config.logChannel);
if (logChannel != null)
{
DiscordEmbed logMessage = new DiscordEmbedBuilder
{
Color = DiscordColor.Green,
Description = "Ticket " + ticketChannel.Mention + " opened by " + member.Mention + ".\n",
Footer = new DiscordEmbedBuilder.EmbedFooter {Text = "Ticket " + ticketID}
};
await logChannel.SendMessageAsync(logMessage);
}
}
internal async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
{
if (!Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
return;
}
internal async Task OnMemberAdded(DiscordClient client, GuildMemberAddEventArgs e)
{
if (!Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
return;
}
foreach (Database.Ticket ticket in ownTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
await channel.AddOverwriteAsync(e.Member, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Green)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket.");
await channel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
foreach (Database.Ticket ticket in ownTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
await channel.AddOverwriteAsync(e.Member, Permissions.AccessChannels, Permissions.None);
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Green)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has rejoined the server, and has been re-added to the ticket.");
await channel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
internal async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e)
{
if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
foreach (Database.Ticket ticket in ownTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server.");
await channel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
internal async Task OnMemberRemoved(DiscordClient client, GuildMemberRemoveEventArgs e)
{
if (Database.TryGetOpenTickets(e.Member.Id, out List<Database.Ticket> ownTickets))
{
foreach(Database.Ticket ticket in ownTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("User '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server.");
await channel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0)
{
DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
if (Database.TryGetAssignedTickets(e.Member.Id, out List<Database.Ticket> assignedTickets) && Config.logChannel != 0)
{
DiscordChannel logChannel = await client.GetChannelAsync(Config.logChannel);
if (logChannel != null)
{
foreach (Database.Ticket ticket in assignedTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">");
await logChannel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
}
}
foreach (Database.Ticket ticket in assignedTickets)
{
try
{
DiscordChannel channel = await client.GetChannelAsync(ticket.channelID);
if (channel?.GuildId == e.Guild.Id)
{
DiscordEmbed message = new DiscordEmbedBuilder()
.WithColor(DiscordColor.Red)
.WithDescription("Assigned staff member '" + e.Member.Username + "#" + e.Member.Discriminator + "' has left the server: <#" + channel.Id + ">");
await logChannel.SendMessageAsync(message);
}
}
catch (Exception) { }
}
}
}
}
private string ParseFailedCheck(CheckBaseAttribute attr)
{
switch (attr)
{
case CooldownAttribute _:
return "You cannot use do that so often!";
case RequireOwnerAttribute _:
return "Only the server owner can use that command!";
case RequirePermissionsAttribute _:
return "You don't have permission to do that!";
case RequireRolesAttribute _:
return "You do not have a required role!";
case RequireUserPermissionsAttribute _:
return "You don't have permission to do that!";
case RequireNsfwAttribute _:
return "This command can only be used in an NSFW channel!";
default:
return "Unknown Discord API error occured, please try again later.";
}
}
}
}
private string ParseFailedCheck(CheckBaseAttribute attr)
{
switch (attr)
{
case CooldownAttribute _:
return "You cannot use do that so often!";
case RequireOwnerAttribute _:
return "Only the server owner can use that command!";
case RequirePermissionsAttribute _:
return "You don't have permission to do that!";
case RequireRolesAttribute _:
return "You do not have a required role!";
case RequireUserPermissionsAttribute _:
return "You don't have permission to do that!";
case RequireNsfwAttribute _:
return "This command can only be used in an NSFW channel!";
default:
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>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, 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="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, 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="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<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 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>

View file

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

View file

@ -1,70 +1,70 @@
<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>
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<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>
<Folder Include="lib\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DSharpPlus" Version="4.2.0" />
<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>
<Reference Include="DiscordChatExporter.Core">
<HintPath>lib\DiscordChatExporter.Core.dll</HintPath>
</Reference>
</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>
<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>

View file

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

View file

@ -15,8 +15,8 @@ namespace SupportChild
{
byte[] box = new byte[1];
do provider.GetBytes(box);
while (!(box[0] < n * (byte.MaxValue / n)));
int k = box[0] % n;
while (!(box[0] < n * (Byte.MaxValue / n)));
int k = (box[0] % n);
n--;
T value = list[k];
list[k] = list[n];
@ -32,11 +32,11 @@ namespace SupportChild
{
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)
{
{
LinkedList<string> messages = new LinkedList<string>();
foreach (string listItem in listItems)
@ -68,4 +68,4 @@ namespace SupportChild
return null;
}
}
}
}

View file

@ -1,84 +1,84 @@
bot:
# Bot token.
token: "<add-token-here>"
# Command prefix.
prefix: "-"
# Channel where ticket logs are posted (recommended)
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)
ticket-category: 000000000000000000
# A message which will open new tickets when users react to it (optional)
reaction-message: 000000000000000000
# Message posted when a ticket is opened.
welcome-message: "Please describe your issue below, and include all information needed for us to help you."
# Decides what messages are shown in console
# Possible values are: Critical, Error, Warning, Information, Debug.
console-log-level: "Information"
# Format for timestamps in transcripts and google sheets if used
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.
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.
# 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
# Sets the type of activity for the bot to display in its presence status
# Possible values are: Playing, Streaming, ListeningTo, Watching, Competing
presence-type: "ListeningTo"
# Sets the activity text shown in the bot's status
presence-text: "-new"
bot:
# Bot token.
token: "<add-token-here>"
# Command prefix.
prefix: "-"
# Channel where ticket logs are posted (recommended)
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)
ticket-category: 000000000000000000
# A message which will open new tickets when users react to it (optional)
reaction-message: 000000000000000000
# Message posted when a ticket is opened.
welcome-message: "Please describe your issue below, and include all information needed for us to help you."
# Decides what messages are shown in console
# Possible values are: Critical, Error, Warning, Information, Debug.
console-log-level: "Information"
# Format for timestamps in transcripts and google sheets if used
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.
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.
# 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
# Sets the type of activity for the bot to display in its presence status
# Possible values are: Playing, Streaming, ListeningTo, Watching, Competing
presence-type: "ListeningTo"
# Sets the activity text shown in the bot's status
presence-text: "-new"
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
# Other staff members and bots do not trigger this.
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.
ticket-updated-delay: 0.5
# Notifies staff when they are assigned to tickets
assignment: true
# Notifies the user opening the ticket that their ticket was closed and includes the transcript
closing: true
# 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.
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.
ticket-updated-delay: 0.5
# Notifies staff when they are assigned to tickets
assignment: true
# Notifies the user opening the ticket that their ticket was closed and includes the transcript
closing: true
database:
# Address and port of the mysql server
address: "127.0.0.1"
port: 3306
# Name of the database to use
name: "supportbot"
# Username and password for authentication
user: ""
password: ""
# Address and port of the mysql server
address: "127.0.0.1"
port: 3306
# Name of the database to use
name: "supportchild"
# Username and password for authentication
user: ""
password: ""
# Set up which roles are allowed to use different commands.
# Example:
# new: [ 000000000000000000, 111111111111111111 ]
# They are grouped into suggested command groups below for first time setup.
permissions:
# Public commands
close: []
list: []
new: []
say: []
status: []
summary: []
transcript: []
# Moderator commands
add: []
addmessage: []
assign: []
blacklist: []
listassigned: []
listoldest: []
listunassigned: []
move: []
rassign: []
removemessage: []
setsummary: []
toggleactive: []
unassign: []
unblacklist: []
# Admin commands
addstaff: []
reload: []
removestaff: []
setticket: []
unsetticket: []
# Public commands
close: []
list: []
new: []
say: []
status: []
summary: []
transcript: []
# Moderator commands
add: []
addmessage: []
assign: []
blacklist: []
listassigned: []
listoldest: []
listunassigned: []
move: []
rassign: []
removemessage: []
setsummary: []
toggleactive: []
unassign: []
unblacklist: []
# Admin commands
addstaff: []
reload: []
removestaff: []
setticket: []
unsetticket: []