diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs new file mode 100644 index 0000000..8fa8282 --- /dev/null +++ b/GlobalSuppressions.cs @@ -0,0 +1,24 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagAddCommand(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagRemoveCommand(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagListCommand(DSharpPlus.SlashCommands.InteractionContext)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagAliasCommand(DSharpPlus.SlashCommands.InteractionContext,System.String,System.String,System.String,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagEditCommand(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagRemoveAlias(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagRenameCommand(DSharpPlus.SlashCommands.InteractionContext,System.String,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagAddAuthor(DSharpPlus.SlashCommands.InteractionContext,System.String,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagColorPicking(DSharpPlus.SlashCommands.InteractionContext,System.String,System.Nullable{UPBot.TagColorValue})~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagImagePicking(DSharpPlus.SlashCommands.InteractionContext,System.String,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagImageRemoving(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagThumbnailPicking(DSharpPlus.SlashCommands.InteractionContext,System.String,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTagsEdit.TagThumbnailRemoving(DSharpPlus.SlashCommands.InteractionContext,System.String)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTimezone.TZTimeGetCommand(DSharpPlus.SlashCommands.InteractionContext,DSharpPlus.Entities.DiscordUser)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTimezone.TZListCommand(DSharpPlus.SlashCommands.InteractionContext)~System.Threading.Tasks.Task")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashTimezone.GetTZScore(System.String,System.String)~System.Int32")] +[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:UPBot.SlashDelete.DeleteCommand(DSharpPlus.SlashCommands.InteractionContext,System.Int64,DSharpPlus.Entities.DiscordUser)~System.Threading.Tasks.Task")] diff --git a/UPBot Code/Actions/CheckSpam.cs b/UPBot Code/Actions/CheckSpam.cs index dac1452..cdd773f 100644 --- a/UPBot Code/Actions/CheckSpam.cs +++ b/UPBot Code/Actions/CheckSpam.cs @@ -8,11 +8,12 @@ /// Command used to check for false nitro links and spam links /// author: CPU /// -public class CheckSpam { - readonly static Regex linkRE = new(@"http[s]?://([^/]+)/"); - readonly static Regex wwwRE = new(@"^w[^\.]{0,3}.\."); - public static DiscordUser SpamCheckTimeout = null; - readonly string[] testLinks = { "discord.com", "discordapp.com", "discord.gg", +namespace UPBot { + public class CheckSpam { + readonly static Regex linkRE = new(@"http[s]?://([^/]+)/"); + readonly static Regex wwwRE = new(@"^w[^\.]{0,3}.\."); + public static DiscordUser SpamCheckTimeout = null; + readonly string[] testLinks = { "discord.com", "discordapp.com", "discord.gg", "discrodapp.com", "discord.org", "discrodgift.com", "discordapp.gift", "humblebundle.com", "microsoft.com", "google.com", @@ -22,7 +23,7 @@ public class CheckSpam { "steamcommunity.com","store.steampowered.com", "steancomunnity.ru", "streamcommunnlty.ru", "streancommunuty.ru", "streamconmunitlu.me", "streamconmunitlu.me", "stearncomminuty.ru", "steamcommunytu.ru", "steamcommnuitry.com", "stearncomunitu.ru", "stearncormunsity.com", "steamcommunytiu.ru", "streammcomunnity.ru", "steamcommunytiy.ru", "stearncommunytiy.ru", "strearncomuniity.ru.com", - "steamcomminytiu.ru", "steamcconuunity.co", "steamcomminytiu.com", "store-stempowered.com", "stemcomnunity.ru.com", "steamcommynitu.ru", + "steamcomminytiu.ru", "steamcconuunity.co", "steamcomminytiu.com", "store-stempowered.com", "stemcomnunity.ru.com", "steamcommynitu.ru", "steamcommurnuity.com", "steamcomminutiu.ru", "steamcommunrlity.com", "steamcommytiny.com", "steamcommunityu.ru", "steamgivenitro.com","steamcommunity.link", "epicgames.com","www.epicgames.com","ww2.epicgames.com","epycgames.com", @@ -37,177 +38,178 @@ public class CheckSpam { }; - public void Test() { - for (int i = 0; i < testLinks.Length; i++) { - float dist = CalculateDistance(testLinks[i], true, true, true, out string probableSite); - bool risk = false; - int leven = 1; - float riskval = 0; - if (dist != 0) { - leven = StringDistance.DLDistance(testLinks[i], probableSite); - riskval = dist / (float)Math.Sqrt(leven); - risk = riskval > 3; + public void Test() { + for (int i = 0; i < testLinks.Length; i++) { + float dist = CalculateDistance(testLinks[i], true, true, true, out string probableSite); + bool risk = false; + int leven = 1; + float riskval = 0; + if (dist != 0) { + leven = StringDistance.DLDistance(testLinks[i], probableSite); + riskval = dist / (float)Math.Sqrt(leven); + risk = riskval > 3; + } + string rvs = riskval.ToString("f2"); + while (rvs.Length < 6) rvs = "0" + rvs; + Console.WriteLine(rvs + " / " + dist.ToString("000") + " / " + leven.ToString("00") + + (risk ? " RISK! " + probableSite : "") + " <= " + testLinks[i] + ); } - string rvs = riskval.ToString("f2"); - while (rvs.Length < 6) rvs = "0" + rvs; - Console.WriteLine(rvs + " / " + dist.ToString("000") + " / " + leven.ToString("00") + - (risk ? " RISK! " + probableSite : "") + " <= " + testLinks[i] - ); - } - } + } - public static int CalculateDistance(string s, bool cdisc, bool csteam, bool cepic, out string siteToCheck) { - siteToCheck = ""; - // Remove the leading www and similar (they cannot be invalid if the rest of the url is valid) - s = wwwRE.Replace(s, ""); - // Remove the domain parts before the 2nd - int pos = s.LastIndexOf('.'); - if (pos > 0) pos = s.LastIndexOf('.', pos - 1); - if (pos > 0) s = s[(pos + 1)..]; - - if (s == "discord.com" || s == "discord.gg" || s == "discord.net" || s == "discordapp.com" || s == "discordapp.net" || s == "discord.gift") return 0; - if (s == "media.discordapp.net" || s == "media.discord.net" || s == "canary.discord.com" || s == "canary.discord.net" || s == "canary.discord.gg") return 0; - if (s == "steamcommunity.com" || s == "store.steampowered.com" || s == "steampowered.com") return 0; - if (s == "epicgames.com") return 0; - if (s == "pastebin.com" || s == "github.com" || s == "controlc.com" || s == "ghostbin.co" || s == "rentry.co" || s == "codiad.com" || s == "zerobin.net" || - s == "toptal.com" || s == "ideone.com" || s == "jsfiddle.net" || s == "textbin.net" || s == "jsbin.com" || s == "ideone.com" || s == "pythondiscord.com") return 0; - - int extra = 0; - if (s.IndexOf("nitro") != -1 || s.IndexOf("gift") != -1 || s.IndexOf("give") != -1) extra = 100; - - // Remove the last part of the url and any leading w??. - if (s.IndexOf('.') != -1) s = s[..s.LastIndexOf('.')]; - - // Check how many substrings of discord.com we have in the string - int valDiscord = 0; - if (cdisc) { - for (int len = 4; len < 8; len++) { - for (int strt = 0; strt < 8 - len; strt++) { - if (s.IndexOf("discord"[strt..(strt + len)]) != -1) - valDiscord += len; + public static int CalculateDistance(string s, bool cdisc, bool csteam, bool cepic, out string siteToCheck) { + siteToCheck = ""; + // Remove the leading www and similar (they cannot be invalid if the rest of the url is valid) + s = wwwRE.Replace(s, ""); + // Remove the domain parts before the 2nd + int pos = s.LastIndexOf('.'); + if (pos > 0) pos = s.LastIndexOf('.', pos - 1); + if (pos > 0) s = s[(pos + 1)..]; + + if (s == "discord.com" || s == "discord.gg" || s == "discord.net" || s == "discordapp.com" || s == "discordapp.net" || s == "discord.gift") return 0; + if (s == "media.discordapp.net" || s == "media.discord.net" || s == "canary.discord.com" || s == "canary.discord.net" || s == "canary.discord.gg") return 0; + if (s == "steamcommunity.com" || s == "store.steampowered.com" || s == "steampowered.com") return 0; + if (s == "epicgames.com") return 0; + if (s == "pastebin.com" || s == "github.com" || s == "controlc.com" || s == "ghostbin.co" || s == "rentry.co" || s == "codiad.com" || s == "zerobin.net" || + s == "toptal.com" || s == "ideone.com" || s == "jsfiddle.net" || s == "textbin.net" || s == "jsbin.com" || s == "ideone.com" || s == "pythondiscord.com") return 0; + + int extra = 0; + if (s.IndexOf("nitro") != -1 || s.IndexOf("gift") != -1 || s.IndexOf("give") != -1) extra = 100; + + // Remove the last part of the url and any leading w??. + if (s.IndexOf('.') != -1) s = s[..s.LastIndexOf('.')]; + + // Check how many substrings of discord.com we have in the string + int valDiscord = 0; + if (cdisc) { + for (int len = 4; len < 8; len++) { + for (int strt = 0; strt < 8 - len; strt++) { + if (s.IndexOf("discord"[strt..(strt + len)]) != -1) + valDiscord += len; + } } - } - if (s.IndexOf("xyz") != -1) valDiscord += 5; - for (int len = 4; len < 7; len++) { - for (int strt = 0; strt < 7 - len; strt++) { - if (s.IndexOf("diczord"[strt..(strt + len)]) != -1) - valDiscord += len; + if (s.IndexOf("xyz") != -1) valDiscord += 5; + for (int len = 4; len < 7; len++) { + for (int strt = 0; strt < 7 - len; strt++) { + if (s.IndexOf("diczord"[strt..(strt + len)]) != -1) + valDiscord += len; + } } } - } - int valSteam1 = 0; - int valSteam2 = 0; - if (csteam) { - for (int len = 5; len < 14; len++) { - for (int strt = 0; strt < 14 - len; strt++) { - if (s.IndexOf("steamcommunity"[strt..(strt+len)]) != -1) - valSteam1 += len; + int valSteam1 = 0; + int valSteam2 = 0; + if (csteam) { + for (int len = 5; len < 14; len++) { + for (int strt = 0; strt < 14 - len; strt++) { + if (s.IndexOf("steamcommunity"[strt..(strt + len)]) != -1) + valSteam1 += len; + } } - } - for (int len = 5; len < 12; len++) { - for (int strt = 0; strt < 12 - len; strt++) { - if (s.IndexOf("steampowered"[strt..(strt + len)]) != -1) - valSteam2 += len; + for (int len = 5; len < 12; len++) { + for (int strt = 0; strt < 12 - len; strt++) { + if (s.IndexOf("steampowered"[strt..(strt + len)]) != -1) + valSteam2 += len; + } } } - } - int valEpic = 0; - if (cepic) { - for (int len = 4; len < 9; len++) { - for (int strt = 0; strt < 9 - len; strt++) { - if (s.IndexOf("epicgames"[strt..(strt + len)]) != -1) - valEpic += len; + int valEpic = 0; + if (cepic) { + for (int len = 4; len < 9; len++) { + for (int strt = 0; strt < 9 - len; strt++) { + if (s.IndexOf("epicgames"[strt..(strt + len)]) != -1) + valEpic += len; + } } } - } - if (s.Contains("discord")) { valDiscord+=2; valSteam1++; valSteam2++; valEpic++; } - if (s.Contains("steam")) { valDiscord++; valSteam1+=2; valSteam2+=2; valEpic++; } - if (s.Contains("epic")) { valDiscord++; valSteam1++; valSteam2++; valEpic+=2; } - - int max = valDiscord; siteToCheck = "discord.com"; - if (valSteam1 > max) { max = valSteam1; siteToCheck = "steamcommunity.com"; } - if (valSteam2 > max) { max = valSteam2; siteToCheck = "steampowered.com"; } - if (valEpic > max) { max = valEpic; siteToCheck = "epicgames.com"; } - return max + extra; - } + if (s.Contains("discord")) { valDiscord += 2; valSteam1++; valSteam2++; valEpic++; } + if (s.Contains("steam")) { valDiscord++; valSteam1 += 2; valSteam2 += 2; valEpic++; } + if (s.Contains("epic")) { valDiscord++; valSteam1++; valSteam2++; valEpic += 2; } + int max = valDiscord; siteToCheck = "discord.com"; + if (valSteam1 > max) { max = valSteam1; siteToCheck = "steamcommunity.com"; } + if (valSteam2 > max) { max = valSteam2; siteToCheck = "steampowered.com"; } + if (valEpic > max) { max = valEpic; siteToCheck = "epicgames.com"; } + return max + extra; + } - internal static async Task CheckMessageUpdate(DiscordClient _, MessageUpdateEventArgs args) { - await CheckMessage(args.Guild, args.Author, args.Message); - } - internal static async Task CheckMessageCreate(DiscordClient _, MessageCreateEventArgs args) { - await CheckMessage(args.Guild, args.Author, args.Message); - } + internal static async Task CheckMessageUpdate(DiscordClient _, MessageUpdateEventArgs args) { + await CheckMessage(args.Guild, args.Author, args.Message); + } - static async Task CheckMessage(DiscordGuild guild, DiscordUser author, DiscordMessage message) { - if (guild == null) return; - if (author == null || author.Id == Configs.BotId) return; // Do not consider myself - if (SpamCheckTimeout != null && SpamCheckTimeout.Id == author.Id) { // Was probably from the setup - SpamCheckTimeout = null; - Utils.Log("Probably self post of spam ignored.", guild.Name); - return; + internal static async Task CheckMessageCreate(DiscordClient _, MessageCreateEventArgs args) { + await CheckMessage(args.Guild, args.Author, args.Message); } - try { - if (!Configs.SpamProtections.ContainsKey(guild.Id)) return; - SpamProtection sp = Configs.SpamProtections[guild.Id]; - if (sp == null) return; - if (!sp.protectDiscord && !sp.protectSteam && !sp.protectDiscord) return; - bool edisc = sp.protectDiscord; - bool esteam = sp.protectSteam; - bool eepic = sp.protectEpic; - - string msg = message.Content.ToLowerInvariant(); - - foreach (Match m in linkRE.Matches(msg)) { - if (!m.Success) continue; - string link = m.Groups[1].Value; - - foreach (var s in Configs.SpamLinks[guild.Id]) { - if (link.IndexOf(s) != -1) { - Utils.Log("Removed spam link message from " + author.Username + ", matched a custom spam link.\noriginal link: " + msg, guild.Name); - DiscordMessage warning = await message.Channel.SendMessageAsync("Removed spam link message from " + author.Username + ", matched a custom spam link.\n" + Configs.GetAdminsMentions(guild.Id) + ", please take care."); - await message.DeleteAsync("Spam link from " + author.Username); - Utils.DeleteDelayed(10000, warning).Wait(); - return; + + static async Task CheckMessage(DiscordGuild guild, DiscordUser author, DiscordMessage message) { + if (guild == null) return; + if (author == null || author.Id == Configs.BotId) return; // Do not consider myself + if (SpamCheckTimeout != null && SpamCheckTimeout.Id == author.Id) { // Was probably from the setup + SpamCheckTimeout = null; + Utils.Log("Probably self post of spam ignored.", guild.Name); + return; + } + try { + if (!Configs.SpamProtections.ContainsKey(guild.Id)) return; + SpamProtection sp = Configs.SpamProtections[guild.Id]; + if (sp == null) return; + if (!sp.protectDiscord && !sp.protectSteam && !sp.protectDiscord) return; + bool edisc = sp.protectDiscord; + bool esteam = sp.protectSteam; + bool eepic = sp.protectEpic; + + string msg = message.Content.ToLowerInvariant(); + + foreach (Match m in linkRE.Matches(msg)) { + if (!m.Success) continue; + string link = m.Groups[1].Value; + + foreach (var s in Configs.SpamLinks[guild.Id]) { + if (link.IndexOf(s) != -1) { + Utils.Log("Removed spam link message from " + author.Username + ", matched a custom spam link.\noriginal link: " + msg, guild.Name); + DiscordMessage warning = await message.Channel.SendMessageAsync("Removed spam link message from " + author.Username + ", matched a custom spam link.\n" + Configs.GetAdminsMentions(guild.Id) + ", please take care."); + await message.DeleteAsync("Spam link from " + author.Username); + Utils.DeleteDelayed(10000, warning).Wait(); + return; + } } - } - bool whitelisted = false; - foreach (var s in Configs.WhiteListLinks[guild.Id]) { - if (link.IndexOf(s) != -1) { - whitelisted = true; - break; + bool whitelisted = false; + foreach (var s in Configs.WhiteListLinks[guild.Id]) { + if (link.IndexOf(s) != -1) { + whitelisted = true; + break; + } } - } - if (whitelisted) continue; - - float dist = CalculateDistance(link, edisc, esteam, eepic, out string probableSite); - if (dist != 0) { - link = link.Replace("app", ""); - - float leven = StringDistance.DLDistance(link, probableSite); - if (link == probableSite) leven = 1; - float riskval = dist / (float)Math.Sqrt(leven); - if (riskval > 3) { - Utils.Log("Removed spam link message from " + author.Username + "\nPossible counterfeit site: " + probableSite + "\noriginal link: " + msg, guild.Name); - DiscordMessage warning = await message.Channel.SendMessageAsync("Removed spam link message from " + author.Username + " possible counterfeit site: " + probableSite + "\n" + Configs.GetAdminsMentions(guild.Id) + ", please take care."); - await message.DeleteAsync("Spam link from " + author.Username); - Utils.DeleteDelayed(10000, warning).Wait(); + if (whitelisted) continue; + + float dist = CalculateDistance(link, edisc, esteam, eepic, out string probableSite); + if (dist != 0) { + link = link.Replace("app", ""); + + float leven = StringDistance.DLDistance(link, probableSite); + if (link == probableSite) leven = 1; + float riskval = dist / (float)Math.Sqrt(leven); + if (riskval > 3) { + Utils.Log("Removed spam link message from " + author.Username + "\nPossible counterfeit site: " + probableSite + "\noriginal link: " + msg, guild.Name); + DiscordMessage warning = await message.Channel.SendMessageAsync("Removed spam link message from " + author.Username + " possible counterfeit site: " + probableSite + "\n" + Configs.GetAdminsMentions(guild.Id) + ", please take care."); + await message.DeleteAsync("Spam link from " + author.Username); + Utils.DeleteDelayed(10000, warning).Wait(); + } } } - } - } catch (NullReferenceException ex) { - Utils.Log(Utils.sttr.ToString(), null); - Utils.Log(ex.Message, null); - Utils.Log(ex.ToString(), null); - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await message.RespondAsync(Utils.GenerateErrorAnswer(guild.Name, "CheckSpam.CheckMessage", ex)); + } catch (NullReferenceException ex) { + Utils.Log(Utils.sttr.ToString(), null); + Utils.Log(ex.Message, null); + Utils.Log(ex.ToString(), null); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await message.RespondAsync(Utils.GenerateErrorAnswer(guild.Name, "CheckSpam.CheckMessage", ex)); + } } } -} +} \ No newline at end of file diff --git a/UPBot Code/Actions/MembersTracking.cs b/UPBot Code/Actions/MembersTracking.cs index 11a3d7d..c20beba 100644 --- a/UPBot Code/Actions/MembersTracking.cs +++ b/UPBot Code/Actions/MembersTracking.cs @@ -4,113 +4,115 @@ using System.Collections.Generic; using System.Threading.Tasks; -public class MembersTracking { - static Dictionary tracking = null; // Use one from COnfig, add nonserializable datetime if we need one +namespace UPBot { + public class MembersTracking { + static Dictionary tracking = null; // Use one from COnfig, add nonserializable datetime if we need one - public static async Task DiscordMemberRemoved(DiscordClient _, DSharpPlus.EventArgs.GuildMemberRemoveEventArgs args) { - try { - TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; - if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackLeave) return; - if (tracking == null) tracking = new Dictionary(); + public static async Task DiscordMemberRemoved(DiscordClient _, DSharpPlus.EventArgs.GuildMemberRemoveEventArgs args) { + try { + TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; + if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackLeave) return; + if (tracking == null) tracking = new Dictionary(); - int daysJ = (int)(DateTime.Now - args.Member.JoinedAt.DateTime).TotalDays; - if (daysJ > 10000) daysJ = -1; // User is probably destroyed. So the value will be not valid + int daysJ = (int)(DateTime.Now - args.Member.JoinedAt.DateTime).TotalDays; + if (daysJ > 10000) daysJ = -1; // User is probably destroyed. So the value will be not valid - if (tracking.ContainsKey(args.Member.Id) || (daysJ >= 0 && daysJ < 2)) { - tracking.Remove(args.Member.Id); - string msg = "User " + args.Member.DisplayName + " did a kiss and go. (" + args.Guild.MemberCount + " members total)"; - await trackChannel.channel.SendMessageAsync(msg); - Utils.Log(msg, args.Guild.Name); - } - else { - string msgC; - if (daysJ >= 0) - msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " (" + args.Member.DisplayName + ") left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " after " + daysJ + " days (" + args.Guild.MemberCount + " members total)"; - else - msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " (" + args.Member.DisplayName + ") left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + args.Guild.MemberCount + " members total)"; - string msgL = "- User " + args.Member.DisplayName + " left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + args.Guild.MemberCount + " members total)"; - await trackChannel.channel.SendMessageAsync(msgC); - Utils.Log(msgL, args.Guild.Name); + if (tracking.ContainsKey(args.Member.Id) || (daysJ >= 0 && daysJ < 2)) { + tracking.Remove(args.Member.Id); + string msg = "User " + args.Member.DisplayName + " did a kiss and go. (" + args.Guild.MemberCount + " members total)"; + await trackChannel.channel.SendMessageAsync(msg); + Utils.Log(msg, args.Guild.Name); + } + else { + string msgC; + if (daysJ >= 0) + msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " (" + args.Member.DisplayName + ") left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " after " + daysJ + " days (" + args.Guild.MemberCount + " members total)"; + else + msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " (" + args.Member.DisplayName + ") left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + args.Guild.MemberCount + " members total)"; + string msgL = "- User " + args.Member.DisplayName + " left on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + args.Guild.MemberCount + " members total)"; + await trackChannel.channel.SendMessageAsync(msgC); + Utils.Log(msgL, args.Guild.Name); + } + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + Utils.Log("Error in DiscordMemberRemoved: " + ex.Message, args.Guild.Name); } - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - Utils.Log("Error in DiscordMemberRemoved: " + ex.Message, args.Guild.Name); - } - await Task.Delay(50); - } + await Task.Delay(50); + } #pragma warning disable IDE0060 // Remove unused parameter - public static async Task DiscordMemberAdded(DiscordClient _client, DSharpPlus.EventArgs.GuildMemberAddEventArgs args) { - try { - TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; - if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackJoin) return; - if (tracking == null) tracking = new Dictionary(); + public static async Task DiscordMemberAdded(DiscordClient _client, DSharpPlus.EventArgs.GuildMemberAddEventArgs args) { + try { + TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; + if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackJoin) return; + if (tracking == null) tracking = new Dictionary(); - tracking[args.Member.Id] = DateTime.Now; - _ = SomethingAsync(trackChannel.channel, args.Member.Id, args.Member.DisplayName, args.Member.Mention, args.Guild.MemberCount); - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - Utils.Log("Error in DiscordMemberAdded: " + ex.Message, args.Guild.Name); + tracking[args.Member.Id] = DateTime.Now; + _ = SomethingAsync(trackChannel.channel, args.Member.Id, args.Member.DisplayName, args.Member.Mention, args.Guild.MemberCount); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + Utils.Log("Error in DiscordMemberAdded: " + ex.Message, args.Guild.Name); + } + await Task.Delay(10); } - await Task.Delay(10); - } #pragma warning restore IDE0060 // Remove unused parameter - public static async Task DiscordMemberUpdated(DiscordClient _, DSharpPlus.EventArgs.GuildMemberUpdateEventArgs args) { - try { - TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; - if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackRoles) return; - if (tracking == null) tracking = new Dictionary(); + public static async Task DiscordMemberUpdated(DiscordClient _, DSharpPlus.EventArgs.GuildMemberUpdateEventArgs args) { + try { + TrackChannel trackChannel = Configs.TrackChannels[args.Guild.Id]; + if (trackChannel == null || trackChannel.channel == null || !trackChannel.trackRoles) return; + if (tracking == null) tracking = new Dictionary(); - IReadOnlyList rolesBefore = args.RolesBefore; - IReadOnlyList rolesAfter = args.RolesAfter; - List rolesAdded = new(); - // Changed role? We can track only additions. Removals are not really sent + IReadOnlyList rolesBefore = args.RolesBefore; + IReadOnlyList rolesAfter = args.RolesAfter; + List rolesAdded = new(); + // Changed role? We can track only additions. Removals are not really sent - foreach (DiscordRole r1 in rolesAfter) { - bool addedRole = true; - foreach (DiscordRole r2 in rolesBefore) { - if (r1.Equals(r2)) { - addedRole = false; - break; + foreach (DiscordRole r1 in rolesAfter) { + bool addedRole = true; + foreach (DiscordRole r2 in rolesBefore) { + if (r1.Equals(r2)) { + addedRole = false; + break; + } } + if (addedRole) rolesAdded.Add(r1); } - if (addedRole) rolesAdded.Add(r1); - } - string msgC; - string msgL; - if (rolesBefore.Count > 0 && rolesAdded.Count > 0) { - msgC = "User " + args.Member.Mention + " has the new role" + (rolesAdded.Count > 1 ? "s:" : ":"); - msgL = "User \"" + args.Member.DisplayName + "\" has the new role" + (rolesAdded.Count > 1 ? "s:" : ":"); - foreach (DiscordRole r in rolesAdded) { - msgC += r.Mention; - msgL += r.Name; + string msgC; + string msgL; + if (rolesBefore.Count > 0 && rolesAdded.Count > 0) { + msgC = "User " + args.Member.Mention + " has the new role" + (rolesAdded.Count > 1 ? "s:" : ":"); + msgL = "User \"" + args.Member.DisplayName + "\" has the new role" + (rolesAdded.Count > 1 ? "s:" : ":"); + foreach (DiscordRole r in rolesAdded) { + msgC += r.Mention; + msgL += r.Name; + } + await trackChannel.channel.SendMessageAsync(msgC); + Utils.Log(msgL, args.Guild.Name); } - await trackChannel.channel.SendMessageAsync(msgC); - Utils.Log(msgL, args.Guild.Name); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + Utils.Log("Error in DiscordMemberUpdated: " + ex.Message, args.Guild.Name); } - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - Utils.Log("Error in DiscordMemberUpdated: " + ex.Message, args.Guild.Name); - } - await Task.Delay(10); - } + await Task.Delay(10); + } - static async Task SomethingAsync(DiscordChannel trackChannel, ulong id, string name, string mention, int numMembers) { - await Task.Delay(25000); - if (tracking.ContainsKey(id)) { - string msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.OK) + " User " + mention + " joined on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + numMembers + " members total)"; - string msgL = "+ User " + name + " joined on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + numMembers + " members total)"; - try { - await trackChannel.SendMessageAsync(msgC); - } catch (Exception e) { - Utils.Log("Cannot post in tracking channel: " + e.Message, trackChannel.Guild.Name); + static async Task SomethingAsync(DiscordChannel trackChannel, ulong id, string name, string mention, int numMembers) { + await Task.Delay(25000); + if (tracking.ContainsKey(id)) { + string msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.OK) + " User " + mention + " joined on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + numMembers + " members total)"; + string msgL = "+ User " + name + " joined on " + DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss") + " (" + numMembers + " members total)"; + try { + await trackChannel.SendMessageAsync(msgC); + } catch (Exception e) { + Utils.Log("Cannot post in tracking channel: " + e.Message, trackChannel.Guild.Name); + } + Utils.Log(msgL, trackChannel.Guild.Name); + tracking.Remove(id); } - Utils.Log(msgL, trackChannel.Guild.Name); - tracking.Remove(id); } } -} +} \ No newline at end of file diff --git a/UPBot Code/Commands/Delete.cs b/UPBot Code/Commands/Delete.cs index e1ad585..6aca5ec 100644 --- a/UPBot Code/Commands/Delete.cs +++ b/UPBot Code/Commands/Delete.cs @@ -10,56 +10,57 @@ /// author: Duck /// /// +namespace UPBot { + public class SlashDelete : ApplicationCommandModule { + /// + /// Delete the last x messages of any user + /// + [SlashCommand("massdel", "Deletes all the last messages (massdel 10) or from a user (massdel @User 10) in the channel")] + public async Task DeleteCommand(InteractionContext ctx, [Option("count", "How many messages to delete")][Minimum(1)][Maximum(50)] long count, [Option("user", "What user' messages to delete")] DiscordUser user = null) { + if (!Configs.HasAdminRole(ctx.Guild.Id, ctx.Member.Roles, false)) { Utils.DefaultNotAllowed(ctx); return; } -public class SlashDelete : ApplicationCommandModule { - /// - /// Delete the last x messages of any user - /// - [SlashCommand("massdel", "Deletes all the last messages (massdel 10) or from a user (massdel @User 10) in the channel")] - public async Task DeleteCommand(InteractionContext ctx, [Option("count", "How many messages to delete")][Minimum(1)][Maximum(50)]long count, [Option("user", "What user' messages to delete")]DiscordUser user=null) { - if (!Configs.HasAdminRole(ctx.Guild.Id, ctx.Member.Roles, false)) { Utils.DefaultNotAllowed(ctx); return; } - - Utils.LogUserCommand(ctx); - if (count <= 0) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", $"You can't delete {count} messages. Try to eat {count} apples, does that make sense?")); - return; - } - else if (count > 50) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", $"You can't delete {count} messages. Try to eat {count} apples, does that make sense?")); - return; - } + Utils.LogUserCommand(ctx); + if (count <= 0) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", $"You can't delete {count} messages. Try to eat {count} apples, does that make sense?")); + return; + } + else if (count > 50) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", $"You can't delete {count} messages. Try to eat {count} apples, does that make sense?")); + return; + } - await ctx.CreateResponseAsync("Deleting..."); + await ctx.CreateResponseAsync("Deleting..."); - try { - int numMsgs = 1; - int numDeleted = 0; - List toDelete = new(); - while (numMsgs < 5 && numDeleted < count) { - int num = (user == null ? (int)count + 2 : 50) * numMsgs; - var messages = await ctx.Channel.GetMessagesAsync(num); - foreach (DiscordMessage m in messages) { - if ((user == null || m.Author.Id == user.Id) && (m.Author.IsBot || !m.Author.IsCurrent)) { - toDelete.Add(m); - numDeleted++; - if (numDeleted >= count) break; + try { + int numMsgs = 1; + int numDeleted = 0; + List toDelete = new(); + while (numMsgs < 5 && numDeleted < count) { + int num = (user == null ? (int)count + 2 : 50) * numMsgs; + var messages = await ctx.Channel.GetMessagesAsync(num); + foreach (DiscordMessage m in messages) { + if ((user == null || m.Author.Id == user.Id) && (m.Author.IsBot || !m.Author.IsCurrent)) { + toDelete.Add(m); + numDeleted++; + if (numDeleted >= count) break; + } } + numMsgs++; } - numMsgs++; - } - await ctx.Channel.DeleteMessagesAsync(toDelete); + await ctx.Channel.DeleteMessagesAsync(toDelete); - try { - await ctx.GetOriginalResponseAsync().Result.DeleteAsync(); - } catch (Exception) { } // Just ignore the exception, it may happen if we try to delete our own message that is already deleted. - if (user != null) - await ctx.Channel.SendMessageAsync($"{numDeleted} messages from {user.Username} deleted"); - else - await ctx.Channel.SendMessageAsync($"{numDeleted} messages deleted"); - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "DeleteMessages", ex)); + try { + await ctx.GetOriginalResponseAsync().Result.DeleteAsync(); + } catch (Exception) { } // Just ignore the exception, it may happen if we try to delete our own message that is already deleted. + if (user != null) + await ctx.Channel.SendMessageAsync($"{numDeleted} messages from {user.Username} deleted"); + else + await ctx.Channel.SendMessageAsync($"{numDeleted} messages deleted"); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "DeleteMessages", ex)); + } } - } + } } \ No newline at end of file diff --git a/UPBot Code/Commands/Refactor.cs b/UPBot Code/Commands/Refactor.cs index 5c3a1dc..5b9676c 100644 --- a/UPBot Code/Commands/Refactor.cs +++ b/UPBot Code/Commands/Refactor.cs @@ -12,432 +12,434 @@ /// /// -public class SlashRefactor : ApplicationCommandModule { - enum Action { - Analyze, - Replace, - Keep - } +namespace UPBot { + public class SlashRefactor : ApplicationCommandModule { + enum Action { + Analyze, + Replace, + Keep + } - enum Langs { - NONE, cs, js, cpp, java, python, Unity - } + enum Langs { + NONE, cs, js, cpp, java, python, Unity + } - [SlashCommand("whatlanguage", "Checks the programming language of a post")] - public async Task CheckLanguage(InteractionContext ctx, [Option("Member", "The user that posted the message to check")] DiscordUser user = null) { - // Checks the language of some code posted - Utils.LogUserCommand(ctx); - - try { - // Get last post that looks like code - ulong usrId = user == null ? 0 : user.Id; - IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); - for (int i = 0; i < msgs.Count; i++) { - DiscordMessage m = msgs[i]; - if (usrId != 0 && m.Author.Id != usrId) continue; - Langs lang = GetBestMatch(m.Content, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn); - string guessed = "no one"; - switch (lang) { - case Langs.cs: guessed = "<:csharp:831465428214743060> C#"; break; - case Langs.js: guessed = "<:Javascript:876103767068647435> Javascript"; break; - case Langs.cpp: guessed = "<:cpp:831465408874676273> C++"; break; - case Langs.java: guessed = "<:java:875852276017815634> Java"; break; - case Langs.python: guessed = "<:python:831465381016895500> Python"; break; - case Langs.Unity: guessed = "<:Unity:968043486379143168> Unity C#"; break; + [SlashCommand("whatlanguage", "Checks the programming language of a post")] + public async Task CheckLanguage(InteractionContext ctx, [Option("Member", "The user that posted the message to check")] DiscordUser user = null) { + // Checks the language of some code posted + Utils.LogUserCommand(ctx); + + try { + // Get last post that looks like code + ulong usrId = user == null ? 0 : user.Id; + IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); + for (int i = 0; i < msgs.Count; i++) { + DiscordMessage m = msgs[i]; + if (usrId != 0 && m.Author.Id != usrId) continue; + Langs lang = GetBestMatch(m.Content, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn); + string guessed = "no one"; + switch (lang) { + case Langs.cs: guessed = "<:csharp:831465428214743060> C#"; break; + case Langs.js: guessed = "<:Javascript:876103767068647435> Javascript"; break; + case Langs.cpp: guessed = "<:cpp:831465408874676273> C++"; break; + case Langs.java: guessed = "<:java:875852276017815634> Java"; break; + case Langs.python: guessed = "<:python:831465381016895500> Python"; break; + case Langs.Unity: guessed = "<:Unity:968043486379143168> Unity C#"; break; + } + string usrname = user == null ? "last code" : user.Username + "'s code"; + await ctx.CreateResponseAsync($"Best guess for the language in {usrname} is: {guessed}\nC# = {weightCs} C++ = {weightCp} Java = {weightJv} Javascript = {weightJs} Python = {weightPy} Unity C# = {weightUn}"); } - string usrname = user == null ? "last code" : user.Username + "'s code"; - await ctx.CreateResponseAsync($"Best guess for the language in {usrname} is: {guessed}\nC# = {weightCs} C++ = {weightCp} Java = {weightJv} Javascript = {weightJs} Python = {weightPy} Unity C# = {weightUn}"); - } - await ctx.CreateResponseAsync("Cannot find something that looks like code."); - } catch (Exception ex) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", ex)); + await ctx.CreateResponseAsync("Cannot find something that looks like code."); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatLanguage", ex)); + } } - } - // Refactors the previous post, if it is code, without removing it - [SlashCommand("format", "Format a specified post (from a user, if specified) as code block")] - public async Task FactorCommand(InteractionContext ctx, [Option("Member", "The user that posted the message to format")] DiscordUser user = null) { - Utils.LogUserCommand(ctx); - - try { - // Get last post that looks like code - DiscordMessage msg = null; - Langs lang = Langs.NONE; - ulong usrId = user == null ? 0 : user.Id; - IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); - for (int i = 0; i < msgs.Count; i++) { - DiscordMessage m = msgs[i]; - if (usrId != 0 && m.Author.Id != usrId) continue; - lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); - if (lang != Langs.NONE) { - msg = m; - break; + // Refactors the previous post, if it is code, without removing it + [SlashCommand("format", "Format a specified post (from a user, if specified) as code block")] + public async Task FactorCommand(InteractionContext ctx, [Option("Member", "The user that posted the message to format")] DiscordUser user = null) { + Utils.LogUserCommand(ctx); + + try { + // Get last post that looks like code + DiscordMessage msg = null; + Langs lang = Langs.NONE; + ulong usrId = user == null ? 0 : user.Id; + IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); + for (int i = 0; i < msgs.Count; i++) { + DiscordMessage m = msgs[i]; + if (usrId != 0 && m.Author.Id != usrId) continue; + lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); + if (lang != Langs.NONE) { + msg = m; + break; + } + } + if (msg == null) { + await ctx.CreateResponseAsync("Cannot find something that looks like code."); + return; } - } - if (msg == null) { - await ctx.CreateResponseAsync("Cannot find something that looks like code."); - return; - } - lang = GetCodeBlock(msg.Content, lang, true, out string code); - - EmojiEnum langEmoji = EmojiEnum.None; - string lmd = ""; - switch (lang) { - case Langs.cs: langEmoji = EmojiEnum.CSharp; lmd = "cs"; break; - case Langs.Unity: langEmoji = EmojiEnum.Unity; lmd = "cs"; break; - case Langs.js: langEmoji = EmojiEnum.Javascript; lmd = "js"; break; - case Langs.cpp: langEmoji = EmojiEnum.Cpp; lmd = "cpp"; break; - case Langs.java: langEmoji = EmojiEnum.Java; lmd = "java"; break; - case Langs.python: langEmoji = EmojiEnum.Python; lmd = "python"; break; - } + lang = GetCodeBlock(msg.Content, lang, true, out string code); + + EmojiEnum langEmoji = EmojiEnum.None; + string lmd = ""; + switch (lang) { + case Langs.cs: langEmoji = EmojiEnum.CSharp; lmd = "cs"; break; + case Langs.Unity: langEmoji = EmojiEnum.Unity; lmd = "cs"; break; + case Langs.js: langEmoji = EmojiEnum.Javascript; lmd = "js"; break; + case Langs.cpp: langEmoji = EmojiEnum.Cpp; lmd = "cpp"; break; + case Langs.java: langEmoji = EmojiEnum.Java; lmd = "java"; break; + case Langs.python: langEmoji = EmojiEnum.Python; lmd = "python"; break; + } - if (langEmoji != EmojiEnum.None && langEmoji != EmojiEnum.Python) code = FixIndentation(code); + if (langEmoji != EmojiEnum.None && langEmoji != EmojiEnum.Python) code = FixIndentation(code); - code = "Reformatted " + msg.Author.Mention + " code\n" + "```" + lmd + "\n" + code + "\n```"; + code = "Reformatted " + msg.Author.Mention + " code\n" + "```" + lmd + "\n" + code + "\n```"; - if (code.Length < 1990) { // Single message - await ctx.CreateResponseAsync(code); - DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + if (code.Length < 1990) { // Single message + await ctx.CreateResponseAsync(code); + DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + } } - } - else { // Split in multiple messages - bool first = true; - while (code.Length > 1995) { - int newlinePos = code.LastIndexOf('\n', 1995); - string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; - code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); - if (first) { - first = false; - await ctx.CreateResponseAsync(codepart); + else { // Split in multiple messages + bool first = true; + while (code.Length > 1995) { + int newlinePos = code.LastIndexOf('\n', 1995); + string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; + code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); + if (first) { + first = false; + await ctx.CreateResponseAsync(codepart); + } + else { + await ctx.Channel.SendMessageAsync(codepart); + } } - else { - await ctx.Channel.SendMessageAsync(codepart); + // Post the last part as is + DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); } } - // Post the last part as is - DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); - } - } - } catch (Exception ex) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Refactor", ex)); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Refactor", ex)); + } } - } - private Langs GetCodeBlock(string content, Langs lang, bool removeEmtpyLines, out string code) { - // Find if we have a code block, and (in case) also a closing codeblock - string writtenLang = null; - code = content; - int cbPos = code.IndexOf("```"); - if (cbPos != -1) { - code = code[(cbPos + 3)..]; - char nl = code[0]; - if (nl != '\r' && nl != '\r') { // We have a possible language - int nlPos1 = code.IndexOf('\n'); - int nlPos2 = code.IndexOf('\r'); - int pos = (nlPos1 != -1) ? nlPos1 : -1; - if (nlPos2 != -1 && (nlPos2 < pos || pos == -1)) pos = nlPos2; - if (pos != -1) { - writtenLang = code[..pos].Trim(' ', '\t', '\r', '\n'); - code = code[pos..].Trim(' ', '\t', '\r', '\n'); + private Langs GetCodeBlock(string content, Langs lang, bool removeEmtpyLines, out string code) { + // Find if we have a code block, and (in case) also a closing codeblock + string writtenLang = null; + code = content; + int cbPos = code.IndexOf("```"); + if (cbPos != -1) { + code = code[(cbPos + 3)..]; + char nl = code[0]; + if (nl != '\r' && nl != '\r') { // We have a possible language + int nlPos1 = code.IndexOf('\n'); + int nlPos2 = code.IndexOf('\r'); + int pos = (nlPos1 != -1) ? nlPos1 : -1; + if (nlPos2 != -1 && (nlPos2 < pos || pos == -1)) pos = nlPos2; + if (pos != -1) { + writtenLang = code[..pos].Trim(' ', '\t', '\r', '\n'); + code = code[pos..].Trim(' ', '\t', '\r', '\n'); + } } + cbPos = code.IndexOf("```"); + if (cbPos != -1) code = code[..(cbPos - 1)].Trim(' ', '\t', '\r', '\n'); } - cbPos = code.IndexOf("```"); - if (cbPos != -1) code = code[..(cbPos - 1)].Trim(' ', '\t', '\r', '\n'); - } - if (removeEmtpyLines) { - code = emptyLines.Replace(code, "\n"); - } - if (writtenLang != null) { // Do another best match with the given language - Langs bl = Langs.NONE; - switch (writtenLang.ToLowerInvariant()) { - case "ph": bl = Langs.python; break; - case "phy": bl = Langs.python; break; - case "phyton": bl = Langs.python; break; - case "pt": bl = Langs.python; break; - case "c": bl = Langs.cpp; break; - case "c++": bl = Langs.cpp; break; - case "cp": bl = Langs.cpp; break; - case "cpp": bl = Langs.cpp; break; - case "cs": bl = Langs.cs; break; - case "csharp": bl = Langs.cs; break; - case "c#": bl = Langs.cs; break; - case "jv": bl = Langs.java; break; - case "java": bl = Langs.java; break; - case "js": bl = Langs.js; break; - case "json": bl = Langs.js; break; - case "jscript": bl = Langs.js; break; - case "javascript": bl = Langs.js; break; + if (removeEmtpyLines) { + code = emptyLines.Replace(code, "\n"); } - return GetBestMatchWithHint(code, bl); + if (writtenLang != null) { // Do another best match with the given language + Langs bl = Langs.NONE; + switch (writtenLang.ToLowerInvariant()) { + case "ph": bl = Langs.python; break; + case "phy": bl = Langs.python; break; + case "phyton": bl = Langs.python; break; + case "pt": bl = Langs.python; break; + case "c": bl = Langs.cpp; break; + case "c++": bl = Langs.cpp; break; + case "cp": bl = Langs.cpp; break; + case "cpp": bl = Langs.cpp; break; + case "cs": bl = Langs.cs; break; + case "csharp": bl = Langs.cs; break; + case "c#": bl = Langs.cs; break; + case "jv": bl = Langs.java; break; + case "java": bl = Langs.java; break; + case "js": bl = Langs.js; break; + case "json": bl = Langs.js; break; + case "jscript": bl = Langs.js; break; + case "javascript": bl = Langs.js; break; + } + return GetBestMatchWithHint(code, bl); + } + return lang; } - return lang; - } - // Refactors the previous post, if it is code, replacing it - [SlashCommand("reformat", "Reformat a specified post as code block, the original message will be deleted")] - public async Task RefactorCommand(InteractionContext ctx, [Option("Member", "The user that posted the message to format")] DiscordUser user = null) { - Utils.LogUserCommand(ctx); - - try { - // Get last post that looks like code - DiscordMessage msg = null; - Langs lang = Langs.NONE; - ulong usrId = user == null ? 0 : user.Id; - IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); - for (int i = 0; i < msgs.Count; i++) { - DiscordMessage m = msgs[i]; - if (usrId != 0 && m.Author.Id != usrId) continue; - lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); - if (lang != Langs.NONE) { - msg = m; - break; + // Refactors the previous post, if it is code, replacing it + [SlashCommand("reformat", "Reformat a specified post as code block, the original message will be deleted")] + public async Task RefactorCommand(InteractionContext ctx, [Option("Member", "The user that posted the message to format")] DiscordUser user = null) { + Utils.LogUserCommand(ctx); + + try { + // Get last post that looks like code + DiscordMessage msg = null; + Langs lang = Langs.NONE; + ulong usrId = user == null ? 0 : user.Id; + IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); + for (int i = 0; i < msgs.Count; i++) { + DiscordMessage m = msgs[i]; + if (usrId != 0 && m.Author.Id != usrId) continue; + lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); + if (lang != Langs.NONE) { + msg = m; + break; + } + } + if (msg == null) { + await ctx.CreateResponseAsync("Cannot find something that looks like code."); + return; } - } - if (msg == null) { - await ctx.CreateResponseAsync("Cannot find something that looks like code."); - return; - } - lang = GetCodeBlock(msg.Content, lang, true, out string code); + lang = GetCodeBlock(msg.Content, lang, true, out string code); - EmojiEnum langEmoji = EmojiEnum.None; - string lmd = ""; - switch (lang) { - case Langs.cs: langEmoji = EmojiEnum.CSharp; lmd = "cs"; break; - case Langs.Unity: langEmoji = EmojiEnum.Unity; lmd = "cs"; break; - case Langs.js: langEmoji = EmojiEnum.Javascript; lmd = "js"; break; - case Langs.cpp: langEmoji = EmojiEnum.Cpp; lmd = "cpp"; break; - case Langs.java: langEmoji = EmojiEnum.Java; lmd = "java"; break; - case Langs.python: langEmoji = EmojiEnum.Python; lmd = "python"; break; - } + EmojiEnum langEmoji = EmojiEnum.None; + string lmd = ""; + switch (lang) { + case Langs.cs: langEmoji = EmojiEnum.CSharp; lmd = "cs"; break; + case Langs.Unity: langEmoji = EmojiEnum.Unity; lmd = "cs"; break; + case Langs.js: langEmoji = EmojiEnum.Javascript; lmd = "js"; break; + case Langs.cpp: langEmoji = EmojiEnum.Cpp; lmd = "cpp"; break; + case Langs.java: langEmoji = EmojiEnum.Java; lmd = "java"; break; + case Langs.python: langEmoji = EmojiEnum.Python; lmd = "python"; break; + } - if (langEmoji != EmojiEnum.None && langEmoji != EmojiEnum.Python) code = FixIndentation(code); + if (langEmoji != EmojiEnum.None && langEmoji != EmojiEnum.Python) code = FixIndentation(code); - code = "Replaced " + msg.Author.Mention + " code (original code has been deleted)\n" + "```" + lmd + "\n" + code + "\n```"; + code = "Replaced " + msg.Author.Mention + " code (original code has been deleted)\n" + "```" + lmd + "\n" + code + "\n```"; - if (code.Length < 1990) { // Single message - await ctx.CreateResponseAsync(code); - DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + if (code.Length < 1990) { // Single message + await ctx.CreateResponseAsync(code); + DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + } } - } - else { // Split in multiple messages - await ctx.DeferAsync(); - await ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource); - while (code.Length > 1995) { - int newlinePos = code.LastIndexOf('\n', 1995); - string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; - code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); - await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent(codepart)); + else { // Split in multiple messages + await ctx.DeferAsync(); + await ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource); + while (code.Length > 1995) { + int newlinePos = code.LastIndexOf('\n', 1995); + string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; + code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); + await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent(codepart)); + } + // Post the last part as is + await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent(code)); + DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + } } - // Post the last part as is - await ctx.EditResponseAsync(new DiscordWebhookBuilder().WithContent(code)); - DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - await replacement.CreateReactionAsync(Utils.GetEmoji(langEmoji)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + + // If we are not an admin, and the message is not from ourselves, do not accept the replace option. + if (Configs.HasAdminRole(ctx.Guild.Id, ctx.Member.Roles, false) || msg.Author.Id != ctx.Member.Id) { + await msg.DeleteAsync(); } - } - // If we are not an admin, and the message is not from ourselves, do not accept the replace option. - if (Configs.HasAdminRole(ctx.Guild.Id, ctx.Member.Roles, false) || msg.Author.Id != ctx.Member.Id) { - await msg.DeleteAsync(); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Refactor", ex)); } - - } catch (Exception ex) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Refactor", ex)); } - } - readonly Regex lineOpenBlock = new("^{(\\s*//.*|\\s*/\\*/.*)?$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex afterOpenBlock = new("^{(.+)?$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex cppModifiers = new("^\\s*(private|public|protected):\\s*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex switchModifiers = new("^(case\\s+[^:]+|default):", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex singleLineBlocksIF = new("^(else\\s+if|if|else)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex singleLineBlocksFOR = new("^for\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex singleLineBlocksFOREACH = new("^foreach\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex singleLineBlocksWHILE = new("^while\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex operatorsEnd = new("(\\+|\\-|\\||\\&|\\^|(\\|\\|)|\\&\\&|\\>\\>|\\<\\<)\\s*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex operatorsStart = new("^(\\+|\\-|\\||\\&|\\^|(\\|\\|)|\\&\\&|\\>\\>|\\<\\<)", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex doubleBrackets = new("{[^\\n]+}", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - readonly Regex closeBrackets = new("[^\n{]+}", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); - - private string FixIndentation(string code) { - string[] prelines = code.Split('\n'); - for (int i = 0; i < prelines.Length; i++) - prelines[i] = prelines[i].Trim(' ', '\t', '\r', '\n'); - - List lines = new(); - foreach (var l in prelines) { - string line = l; - bool found = true; - while (found) { - if (doubleBrackets.IsMatch(line)) { - // Check it is not inside a string - bool instrings = false; - bool instringd = false; - int pos = 1; - bool afterfirst = false; - foreach (char c in line) { - if (c == '"') instringd = !instringd; - if (c == '\'') instrings = !instrings; - if (c == '{' && pos != 1) { - afterfirst = true; - break; + readonly Regex lineOpenBlock = new("^{(\\s*//.*|\\s*/\\*/.*)?$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex afterOpenBlock = new("^{(.+)?$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex cppModifiers = new("^\\s*(private|public|protected):\\s*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex switchModifiers = new("^(case\\s+[^:]+|default):", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex singleLineBlocksIF = new("^(else\\s+if|if|else)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex singleLineBlocksFOR = new("^for\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex singleLineBlocksFOREACH = new("^foreach\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex singleLineBlocksWHILE = new("^while\\s*\\([^\\)]+\\)[^;{\\n]*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex operatorsEnd = new("(\\+|\\-|\\||\\&|\\^|(\\|\\|)|\\&\\&|\\>\\>|\\<\\<)\\s*$", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex operatorsStart = new("^(\\+|\\-|\\||\\&|\\^|(\\|\\|)|\\&\\&|\\>\\>|\\<\\<)", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex doubleBrackets = new("{[^\\n]+}", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + readonly Regex closeBrackets = new("[^\n{]+}", RegexOptions.Multiline, TimeSpan.FromSeconds(10)); + + private string FixIndentation(string code) { + string[] prelines = code.Split('\n'); + for (int i = 0; i < prelines.Length; i++) + prelines[i] = prelines[i].Trim(' ', '\t', '\r', '\n'); + + List lines = new(); + foreach (var l in prelines) { + string line = l; + bool found = true; + while (found) { + if (doubleBrackets.IsMatch(line)) { + // Check it is not inside a string + bool instrings = false; + bool instringd = false; + int pos = 1; + bool afterfirst = false; + foreach (char c in line) { + if (c == '"') instringd = !instringd; + if (c == '\'') instrings = !instrings; + if (c == '{' && pos != 1) { + afterfirst = true; + break; + } + pos++; } - pos++; - } - if (!instringd && !instrings && afterfirst) { - lines.Add(line[..pos].Trim(' ', '\t', '\r', '\n')); - line = line[pos..].Trim(' ', '\t', '\r', '\n'); - } - else { - lines.Add(line); - found = false; - } - } - else if (closeBrackets.IsMatch(line)) { - // Check it is not inside a string - bool instrings = false; - bool instringd = false; - int pos = 0; - bool afterfirst = false; - foreach (char c in line) { - if (c == '"') instringd = !instringd; - if (c == '\'') instrings = !instrings; - if (c == '}' && pos != 0) { - afterfirst = true; - break; + if (!instringd && !instrings && afterfirst) { + lines.Add(line[..pos].Trim(' ', '\t', '\r', '\n')); + line = line[pos..].Trim(' ', '\t', '\r', '\n'); + } + else { + lines.Add(line); + found = false; } - pos++; } - if (!instringd && !instrings && afterfirst) { - lines.Add(line[..pos].Trim(' ', '\t', '\r', '\n')); - line = line[pos..].Trim(' ', '\t', '\r', '\n'); + else if (closeBrackets.IsMatch(line)) { + // Check it is not inside a string + bool instrings = false; + bool instringd = false; + int pos = 0; + bool afterfirst = false; + foreach (char c in line) { + if (c == '"') instringd = !instringd; + if (c == '\'') instrings = !instrings; + if (c == '}' && pos != 0) { + afterfirst = true; + break; + } + pos++; + } + if (!instringd && !instrings && afterfirst) { + lines.Add(line[..pos].Trim(' ', '\t', '\r', '\n')); + line = line[pos..].Trim(' ', '\t', '\r', '\n'); + } + else { + lines.Add(line); + found = false; + } } else { lines.Add(line); found = false; } } - else { - lines.Add(line); - found = false; - } } - } - for (int i = 1; i < lines.Count; i++) { - if (lineOpenBlock.IsMatch(lines[i])) { - lines[i - 1] += " " + lines[i]; - lines[i] = null; - } else { - Match afterOpen = afterOpenBlock.Match(lines[i]); - if (afterOpen.Success) { - lines[i - 1] += " { "; - lines[i] = afterOpen.Groups[1].Value.Trim(' ', '\t', '\r', '\n'); + for (int i = 1; i < lines.Count; i++) { + if (lineOpenBlock.IsMatch(lines[i])) { + lines[i - 1] += " " + lines[i]; + lines[i] = null; + } + else { + Match afterOpen = afterOpenBlock.Match(lines[i]); + if (afterOpen.Success) { + lines[i - 1] += " { "; + lines[i] = afterOpen.Groups[1].Value.Trim(' ', '\t', '\r', '\n'); + } } } + int indent = 0; + string res = ""; + bool nextLineIndent = false; + for (int i = 0; i < lines.Count; i++) { + bool tempRemoveIndent = false; + string line = lines[i]; + if (line == null) continue; + if (line.IndexOf('}') != -1 && !line.Contains('{')) indent--; + if (cppModifiers.IsMatch(line) || switchModifiers.IsMatch(line)) tempRemoveIndent = true; + + string tabs = ""; + for (int j = tempRemoveIndent ? 1 : 0; j < (nextLineIndent ? indent + 1 : indent); j++) tabs += " "; + if (operatorsStart.IsMatch(line)) tabs += " "; + if (singleLineBlocksIF.IsMatch(line) || singleLineBlocksFOR.IsMatch(line) || singleLineBlocksFOREACH.IsMatch(line) || singleLineBlocksWHILE.IsMatch(line) || operatorsEnd.IsMatch(line)) + nextLineIndent = true; + else nextLineIndent = false; + res += tabs + line + "\n"; + if (line.IndexOf('{') != -1 && !line.Contains('}')) indent++; + } + return res; } - int indent = 0; - string res = ""; - bool nextLineIndent = false; - for (int i = 0; i < lines.Count; i++) { - bool tempRemoveIndent = false; - string line = lines[i]; - if (line == null) continue; - if (line.IndexOf('}') != -1 && !line.Contains('{')) indent--; - if (cppModifiers.IsMatch(line) || switchModifiers.IsMatch(line)) tempRemoveIndent = true; - - string tabs = ""; - for (int j = tempRemoveIndent ? 1 : 0; j < (nextLineIndent ? indent + 1 : indent); j++) tabs += " "; - if (operatorsStart.IsMatch(line)) tabs += " "; - if (singleLineBlocksIF.IsMatch(line) || singleLineBlocksFOR.IsMatch(line) || singleLineBlocksFOREACH.IsMatch(line) || singleLineBlocksWHILE.IsMatch(line) || operatorsEnd.IsMatch(line)) - nextLineIndent = true; - else nextLineIndent = false; - res += tabs + line + "\n"; - if (line.IndexOf('{') != -1 && !line.Contains('}')) indent++; - } - return res; - } - private Langs GetBestMatchWithHint(string code, Langs hint) { - _ = GetBestMatch(code, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn); - switch (hint) { - case Langs.cs: weightCs += 10; break; - case Langs.js: weightJs += 10; break; - case Langs.cpp: weightCp += 10; break; - case Langs.java: weightJv += 10; break; - case Langs.python: weightPy += 10; break; - case Langs.Unity: weightUn += 10; break; + private Langs GetBestMatchWithHint(string code, Langs hint) { + _ = GetBestMatch(code, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn); + switch (hint) { + case Langs.cs: weightCs += 10; break; + case Langs.js: weightJs += 10; break; + case Langs.cpp: weightCp += 10; break; + case Langs.java: weightJv += 10; break; + case Langs.python: weightPy += 10; break; + case Langs.Unity: weightUn += 10; break; + } + Langs res = Langs.NONE; + int w = 0; + if (weightCs > w) { w = weightCs; res = Langs.cs; } + if (weightUn > w) { w = weightUn; res = Langs.Unity; } + if (weightCp > w) { w = weightCp; res = Langs.cpp; } + if (weightJs > w) { w = weightJs; res = Langs.js; } + if (weightJv > w) { w = weightJv; res = Langs.java; } + if (weightPy > w) { res = Langs.python; } + return res; } - Langs res = Langs.NONE; - int w = 0; - if (weightCs > w) { w = weightCs; res = Langs.cs; } - if (weightUn > w) { w = weightUn; res = Langs.Unity; } - if (weightCp > w) { w = weightCp; res = Langs.cpp; } - if (weightJs > w) { w = weightJs; res = Langs.js; } - if (weightJv > w) { w = weightJv; res = Langs.java; } - if (weightPy > w) { res = Langs.python; } - return res; - } - private Langs GetBestMatch(string code, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn) { - if (code.Length > 4 && code[..3] == "```" && code.IndexOf('\n') != -1) { - code = code[(code.IndexOf('\n') + 1)..]; - } - if (code.Length > 4 && code[^3..] == "```") { - code = code[..^3]; - } - weightCs = 0; weightCp = 0; weightJv = 0; weightJs = 0; weightPy = 0; weightUn = 0; - foreach (LangKWord k in keywords) { - if (k.regexp.IsMatch(code)) { - weightCs += k.wCs; - weightCp += k.wCp; - weightJv += k.wJv; - weightJs += k.wJs; - weightPy += k.wPy; - weightUn += k.wUn; + private Langs GetBestMatch(string code, out int weightCs, out int weightCp, out int weightJv, out int weightJs, out int weightPy, out int weightUn) { + if (code.Length > 4 && code[..3] == "```" && code.IndexOf('\n') != -1) { + code = code[(code.IndexOf('\n') + 1)..]; + } + if (code.Length > 4 && code[^3..] == "```") { + code = code[..^3]; } + weightCs = 0; weightCp = 0; weightJv = 0; weightJs = 0; weightPy = 0; weightUn = 0; + foreach (LangKWord k in keywords) { + if (k.regexp.IsMatch(code)) { + weightCs += k.wCs; + weightCp += k.wCp; + weightJv += k.wJv; + weightJs += k.wJs; + weightPy += k.wPy; + weightUn += k.wUn; + } + } + int w = 0; + Langs res = Langs.NONE; + if (weightCs > w) { w = weightCs; res = Langs.cs; } + if (weightUn > w) { w = weightUn; res = Langs.Unity; } + if (weightCp > w) { w = weightCp; res = Langs.cpp; } + if (weightJs > w) { w = weightJs; res = Langs.js; } + if (weightJv > w) { w = weightJv; res = Langs.java; } + if (weightPy > w) { res = Langs.python; } + return res; } - int w = 0; - Langs res = Langs.NONE; - if (weightCs > w) { w = weightCs; res = Langs.cs; } - if (weightUn > w) { w = weightUn; res = Langs.Unity; } - if (weightCp > w) { w = weightCp; res = Langs.cpp; } - if (weightJs > w) { w = weightJs; res = Langs.js; } - if (weightJv > w) { w = weightJv; res = Langs.java; } - if (weightPy > w) { res = Langs.python; } - return res; - } - readonly Regex emptyLines = new("(\\r?\\n\\s*){1,}(\\r?\\n)", RegexOptions.Singleline, TimeSpan.FromSeconds(10)); + readonly Regex emptyLines = new("(\\r?\\n\\s*){1,}(\\r?\\n)", RegexOptions.Singleline, TimeSpan.FromSeconds(10)); - readonly LangKWord[] keywords = { + readonly LangKWord[] keywords = { new LangKWord{regexp = new("getline", RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10)), wCs = 0, wCp = 5, wJv = 0, wJs = 0, wPy = 0, wUn = 0 }, new LangKWord{regexp = new("cin", RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10)), wCs = 0, wCp = 5, wJv = 0, wJs = 0, wPy = 0, wUn = 0 }, new LangKWord{regexp = new("cout", RegexOptions.IgnoreCase, TimeSpan.FromSeconds(10)), wCs = 0, wCp = 5, wJv = 0, wJs = 0, wPy = 0, wUn = 0 }, @@ -519,100 +521,101 @@ private Langs GetBestMatch(string code, out int weightCs, out int weightCp, out new LangKWord{regexp = new("\\-\\>", RegexOptions.None, TimeSpan.FromSeconds(10)), wCs = 0, wCp = 9, wJv = 0, wJs = 0, wPy = 0, wUn = 0 }, }; - public class LangKWord { - public Regex regexp; - public int wCs; // Weight for C# - public int wCp; // Weight for C++ - public int wJv; // Weight for Java - public int wJs; // Weight for Javascript - public int wPy; // Weight for Python - public int wUn; // Weight for Unity - } + public class LangKWord { + public Regex regexp; + public int wCs; // Weight for C# + public int wCp; // Weight for C++ + public int wJv; // Weight for Java + public int wJs; // Weight for Javascript + public int wPy; // Weight for Python + public int wUn; // Weight for Unity + } - [SlashCommand("addlinenumbers", "Grabs a some and adds line numbers before")] - public async Task AddLineNumbers(InteractionContext ctx, [Option("Member", "The user that posted the code")] DiscordUser user = null) { - // Checks the language of some code posted - Utils.LogUserCommand(ctx); - - try { - // Get last post that looks like code - DiscordMessage msg = null; - Langs lang = Langs.NONE; - ulong usrId = user == null ? 0 : user.Id; - IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); - for (int i = 0; i < msgs.Count; i++) { - DiscordMessage m = msgs[i]; - if (usrId != 0 && m.Author.Id != usrId) continue; - lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); - if (lang != Langs.NONE) { - msg = m; - break; + [SlashCommand("addlinenumbers", "Grabs a some and adds line numbers before")] + public async Task AddLineNumbers(InteractionContext ctx, [Option("Member", "The user that posted the code")] DiscordUser user = null) { + // Checks the language of some code posted + Utils.LogUserCommand(ctx); + + try { + // Get last post that looks like code + DiscordMessage msg = null; + Langs lang = Langs.NONE; + ulong usrId = user == null ? 0 : user.Id; + IReadOnlyList msgs = await ctx.Channel.GetMessagesAsync(50); + for (int i = 0; i < msgs.Count; i++) { + DiscordMessage m = msgs[i]; + if (usrId != 0 && m.Author.Id != usrId) continue; + lang = GetBestMatch(m.Content, out _, out _, out _, out _, out _, out _); + if (lang != Langs.NONE) { + msg = m; + break; + } + } + if (msg == null) { + await ctx.CreateResponseAsync("Cannot find something that looks like code."); + return; } - } - if (msg == null) { - await ctx.CreateResponseAsync("Cannot find something that looks like code."); - return; - } - lang = GetCodeBlock(msg.Content, lang, false, out string srccode); - string lmd = ""; - switch (lang) { - case Langs.cs: lmd = "cs"; break; - case Langs.Unity: lmd = "cs"; break; - case Langs.js: lmd = "js"; break; - case Langs.cpp: lmd = "cpp"; break; - case Langs.java: lmd = "java"; break; - case Langs.python: lmd = "python"; break; - } + lang = GetCodeBlock(msg.Content, lang, false, out string srccode); + string lmd = ""; + switch (lang) { + case Langs.cs: lmd = "cs"; break; + case Langs.Unity: lmd = "cs"; break; + case Langs.js: lmd = "js"; break; + case Langs.cpp: lmd = "cpp"; break; + case Langs.java: lmd = "java"; break; + case Langs.python: lmd = "python"; break; + } - string[] codelines = srccode.Split('\n'); - string code = "```" + lmd + "\n"; + string[] codelines = srccode.Split('\n'); + string code = "```" + lmd + "\n"; - for (int i = 0; i < codelines.Length; i++) { - string ln = (i + 1).ToString(); - if (i + 1 < 10) ln = " " + ln; - if (i + 1 < 100) ln = " " + ln; - code += ln + " " + codelines[i] + "\n"; - } - code += "```"; - - if (code.Length < 1990) { // Single message - await ctx.CreateResponseAsync(code); - DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + for (int i = 0; i < codelines.Length; i++) { + string ln = (i + 1).ToString(); + if (i + 1 < 10) ln = " " + ln; + if (i + 1 < 100) ln = " " + ln; + code += ln + " " + codelines[i] + "\n"; } - } - else { // Split in multiple messages - bool first = true; - while (code.Length > 1995) { - int newlinePos = code.LastIndexOf('\n', 1995); - string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; - code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); - if (first) { - first = false; - await ctx.CreateResponseAsync(codepart); - } - else { - await ctx.Channel.SendMessageAsync(codepart); + code += "```"; + + if (code.Length < 1990) { // Single message + await ctx.CreateResponseAsync(code); + DiscordMessage replacement = await ctx.GetOriginalResponseAsync(); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); } } - // Post the last part as is - DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); - try { - await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); - } catch (Exception e) { - Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + else { // Split in multiple messages + bool first = true; + while (code.Length > 1995) { + int newlinePos = code.LastIndexOf('\n', 1995); + string codepart = code[..newlinePos].Trim(' ', '\t', '\r', '\n') + "\n```"; + code = "```" + lmd + "\n" + code[(newlinePos + 1)..].Trim('\r', '\n'); + if (first) { + first = false; + await ctx.CreateResponseAsync(codepart); + } + else { + await ctx.Channel.SendMessageAsync(codepart); + } + } + // Post the last part as is + DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); + try { + await replacement.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.AutoRefactored)); + } catch (Exception e) { + Utils.Log("Cannot add an emoji: " + e.Message, ctx.Guild.Name); + } } - } - } catch (Exception ex) { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "AddLineNumbers", ex)); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "AddLineNumbers", ex)); + } } - } + } } \ No newline at end of file diff --git a/UPBot Code/Commands/Setup.cs b/UPBot Code/Commands/Setup.cs index 9e4d205..727b816 100644 --- a/UPBot Code/Commands/Setup.cs +++ b/UPBot Code/Commands/Setup.cs @@ -7,735 +7,729 @@ using DSharpPlus.Interactivity.Extensions; using DSharpPlus.SlashCommands; -/// -/// This command is used to configure the bot, so roles and messages can be set for other servers. -/// author: CPU -/// -public class SlashSetup : ApplicationCommandModule { - - readonly DiscordComponentEmoji ey = new(DiscordEmoji.FromUnicode("✅")); - readonly DiscordComponentEmoji en = new(DiscordEmoji.FromUnicode("❎")); - readonly DiscordComponentEmoji el = new(DiscordEmoji.FromUnicode("↖️")); - readonly DiscordComponentEmoji er = new(DiscordEmoji.FromUnicode("↘️")); - readonly DiscordComponentEmoji ec = new(DiscordEmoji.FromUnicode("❌")); - static DiscordComponentEmoji ok = null; - static DiscordComponentEmoji ko = null; - - - [SlashCommand("setup", "Configuration of the features")] - public async Task SetupCommand(InteractionContext ctx, [Option("Command", "Show, List, Admins, or Dump")] SetupCommandItem? command = null) { - if (ctx.Guild == null) { - await ctx.CreateResponseAsync("I cannot be used in Direct Messages.", true); - return; - } - Utils.LogUserCommand(ctx); - DiscordGuild g = ctx.Guild; - ulong gid = g.Id; +namespace UPBot { + /// + /// This command is used to configure the bot, so roles and messages can be set for other servers. + /// author: CPU + /// + public class SlashSetup : ApplicationCommandModule { + + readonly DiscordComponentEmoji ey = new(DiscordEmoji.FromUnicode("✅")); + readonly DiscordComponentEmoji en = new(DiscordEmoji.FromUnicode("❎")); + readonly DiscordComponentEmoji el = new(DiscordEmoji.FromUnicode("↖️")); + readonly DiscordComponentEmoji er = new(DiscordEmoji.FromUnicode("↘️")); + readonly DiscordComponentEmoji ec = new(DiscordEmoji.FromUnicode("❌")); + static DiscordComponentEmoji ok = null; + static DiscordComponentEmoji ko = null; + + + [SlashCommand("setup", "Configuration of the features")] + public async Task SetupCommand(InteractionContext ctx, [Option("Command", "Show, List, Admins, or Dump")] SetupCommandItem? command = null) { + if (ctx.Guild == null) { + await ctx.CreateResponseAsync("I cannot be used in Direct Messages.", true); + return; + } + Utils.LogUserCommand(ctx); + DiscordGuild g = ctx.Guild; + ulong gid = g.Id; - if (!Configs.HasAdminRole(gid, ctx.Member.Roles, false)) { - await ctx.CreateResponseAsync("Only admins can setup the bot.", true); - return; - } + if (!Configs.HasAdminRole(gid, ctx.Member.Roles, false)) { + await ctx.CreateResponseAsync("Only admins can setup the bot.", true); + return; + } - if (command == null || command == SetupCommandItem.Show) await HandleSetupInteraction(ctx, gid); - else if (command == SetupCommandItem.List) await ctx.CreateResponseAsync(GenerateSetupList(g, gid)); - else if (command == SetupCommandItem.Save) { - string theList = GenerateSetupList(g, gid); - string rndName = "SetupList" + DateTime.Now.Second + "Tmp" + DateTime.Now.Millisecond + ".txt"; - File.WriteAllText(rndName, theList); - using var fs = new FileStream(rndName, FileMode.Open, FileAccess.Read); - await ctx.CreateResponseAsync(new DiscordInteractionResponseBuilder().WithContent("Setup List in attachment").AddFile(fs)); - await Utils.DeleteFileDelayed(30, rndName); + if (command == null || command == SetupCommandItem.Show) await HandleSetupInteraction(ctx, gid); + else if (command == SetupCommandItem.List) await ctx.CreateResponseAsync(GenerateSetupList(g, gid)); + else if (command == SetupCommandItem.Save) { + string theList = GenerateSetupList(g, gid); + string rndName = "SetupList" + DateTime.Now.Second + "Tmp" + DateTime.Now.Millisecond + ".txt"; + File.WriteAllText(rndName, theList); + using var fs = new FileStream(rndName, FileMode.Open, FileAccess.Read); + await ctx.CreateResponseAsync(new DiscordInteractionResponseBuilder().WithContent("Setup List in attachment").AddFile(fs)); + await Utils.DeleteFileDelayed(30, rndName); + } + else await ctx.CreateResponseAsync("Wrong choice", true); } - else await ctx.CreateResponseAsync("Wrong choice", true); - } - async Task HandleSetupInteraction(InteractionContext ctx, ulong gid) { - var interact = ctx.Client.GetInteractivity(); - if (ok == null) { - ok = new DiscordComponentEmoji(Utils.GetEmoji(EmojiEnum.OK)); - ko = new DiscordComponentEmoji(Utils.GetEmoji(EmojiEnum.KO)); - } + async Task HandleSetupInteraction(InteractionContext ctx, ulong gid) { + var interact = ctx.Client.GetInteractivity(); + if (ok == null) { + ok = new DiscordComponentEmoji(Utils.GetEmoji(EmojiEnum.OK)); + ko = new DiscordComponentEmoji(Utils.GetEmoji(EmojiEnum.KO)); + } - // Basic intro message - CreateMainConfigPage(ctx, null); + // Basic intro message + CreateMainConfigPage(ctx, null); - DiscordMessage msg = await ctx.GetOriginalResponseAsync(); - var result = await interact.WaitForButtonAsync(msg, TimeSpan.FromMinutes(2)); - var interRes = result.Result; - await msg.DeleteAsync(); - msg = null; + DiscordMessage msg = await ctx.GetOriginalResponseAsync(); + var result = await interact.WaitForButtonAsync(msg, TimeSpan.FromMinutes(2)); + var interRes = result.Result; + await msg.DeleteAsync(); + msg = null; - while (interRes != null && interRes.Id != "idexitconfig") { - interRes.Handled = true; - string cmdId = interRes.Id; + while (interRes != null && interRes.Id != "idexitconfig") { + interRes.Handled = true; + string cmdId = interRes.Id; - // ******************************************************************** Back ************************************************************************* - if (cmdId == "idback") { - msg = FollowMainConfigPage(ctx, msg); - } + // ******************************************************************** Back ************************************************************************* + if (cmdId == "idback") { + msg = FollowMainConfigPage(ctx, msg); + } - // ***************************************************** DefAdmins *********************************************************************************** - else if (cmdId == "iddefineadmins") { - msg = CreateAdminsInteraction(ctx, msg); - } + // ***************************************************** DefAdmins *********************************************************************************** + else if (cmdId == "iddefineadmins") { + msg = CreateAdminsInteraction(ctx, msg); + } - // *********************************************************** DefAdmins.AddRole ******************************************************************************* - else if (cmdId == "idroleadd") { - await ctx.Channel.DeleteMessageAsync(msg); - DiscordMessage prompt = await ctx.Channel.SendMessageAsync(ctx.Member.Mention + ", please mention the roles to add (_type anything else to close_)"); - var answer = await interact.WaitForMessageAsync((dm) => { - return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); - }, TimeSpan.FromMinutes(2)); - if (answer.Result != null) { - if (answer.Result.MentionedRoles.Count > 0) { - foreach (var dr in answer.Result.MentionedRoles) { - if (!Configs.AdminRoles[gid].Contains(dr.Id)) { - Configs.AdminRoles[gid].Add(dr.Id); - Database.Add(new AdminRole(gid, dr.Id)); + // *********************************************************** DefAdmins.AddRole ******************************************************************************* + else if (cmdId == "idroleadd") { + await ctx.Channel.DeleteMessageAsync(msg); + DiscordMessage prompt = await ctx.Channel.SendMessageAsync(ctx.Member.Mention + ", please mention the roles to add (_type anything else to close_)"); + var answer = await interact.WaitForMessageAsync((dm) => { + return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); + }, TimeSpan.FromMinutes(2)); + if (answer.Result != null) { + if (answer.Result.MentionedRoles.Count > 0) { + foreach (var dr in answer.Result.MentionedRoles) { + if (!Configs.AdminRoles[gid].Contains(dr.Id)) { + Configs.AdminRoles[gid].Add(dr.Id); + Database.Add(new AdminRole(gid, dr.Id)); + } } } - } - else { // Try to find if we have a role with the typed name - string rname = answer.Result.Content.Trim(); - foreach (var role in ctx.Guild.Roles.Values) { - if (role.Name.Equals(rname, StringComparison.InvariantCultureIgnoreCase)) { - if (!Configs.AdminRoles[gid].Contains(role.Id)) { - Configs.AdminRoles[gid].Add(role.Id); - Database.Add(new AdminRole(gid, role.Id)); + else { // Try to find if we have a role with the typed name + string rname = answer.Result.Content.Trim(); + foreach (var role in ctx.Guild.Roles.Values) { + if (role.Name.Equals(rname, StringComparison.InvariantCultureIgnoreCase)) { + if (!Configs.AdminRoles[gid].Contains(role.Id)) { + Configs.AdminRoles[gid].Add(role.Id); + Database.Add(new AdminRole(gid, role.Id)); + } } } } } + + await ctx.Channel.DeleteMessageAsync(prompt); + msg = CreateAdminsInteraction(ctx, null); } - await ctx.Channel.DeleteMessageAsync(prompt); - msg = CreateAdminsInteraction(ctx, null); - } + // *********************************************************** DefAdmins.RemRole ******************************************************************************* + else if (cmdId.Length > 8 && cmdId[0..9] == "idrolerem") { + await ctx.Channel.DeleteMessageAsync(msg); + if (int.TryParse(cmdId[9..], out int rpos)) { + ulong rid = Configs.AdminRoles[ctx.Guild.Id][rpos]; ; + Database.DeleteByKeys(gid, rid); + Configs.AdminRoles[ctx.Guild.Id].RemoveAt(rpos); + } - // *********************************************************** DefAdmins.RemRole ******************************************************************************* - else if (cmdId.Length > 8 && cmdId[0..9] == "idrolerem") { - await ctx.Channel.DeleteMessageAsync(msg); - if (int.TryParse(cmdId[9..], out int rpos)) { - ulong rid = Configs.AdminRoles[ctx.Guild.Id][rpos]; ; - Database.DeleteByKeys(gid, rid); - Configs.AdminRoles[ctx.Guild.Id].RemoveAt(rpos); + msg = CreateAdminsInteraction(ctx, null); } - msg = CreateAdminsInteraction(ctx, null); - } + // ************************************************************ DefTracking ************************************************************************** + else if (cmdId == "iddefinetracking") { + msg = CreateTrackingInteraction(ctx, msg); + } - // ************************************************************ DefTracking ************************************************************************** - else if (cmdId == "iddefinetracking") { - msg = CreateTrackingInteraction(ctx, msg); - } + // ************************************************************ DefTracking.Change Channel ************************************************************************ + else if (cmdId == "idchangetrackch") { + await ctx.Channel.DeleteMessageAsync(msg); + DiscordMessage prompt = await ctx.Channel.SendMessageAsync(ctx.Member.Mention + ", please mention the channel (_use: **#**_) as tracking channel\nType _remove_ to remove the tracking channel"); + var answer = await interact.WaitForMessageAsync((dm) => { + return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id && (dm.MentionedChannels.Count > 0 || dm.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase))); + }, TimeSpan.FromMinutes(2)); + if (answer.Result == null || (answer.Result.MentionedChannels.Count == 0 && !answer.Result.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase))) { + await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config timed out")); + return; + } - // ************************************************************ DefTracking.Change Channel ************************************************************************ - else if (cmdId == "idchangetrackch") { - await ctx.Channel.DeleteMessageAsync(msg); - DiscordMessage prompt = await ctx.Channel.SendMessageAsync(ctx.Member.Mention + ", please mention the channel (_use: **#**_) as tracking channel\nType _remove_ to remove the tracking channel"); - var answer = await interact.WaitForMessageAsync((dm) => { - return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id && (dm.MentionedChannels.Count > 0 || dm.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase))); - }, TimeSpan.FromMinutes(2)); - if (answer.Result == null || (answer.Result.MentionedChannels.Count == 0 && !answer.Result.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase))) { - await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config timed out")); - return; - } + if (answer.Result.MentionedChannels.Count > 0) { + if (Configs.TrackChannels[gid] == null) { + TrackChannel tc = new(); + Configs.TrackChannels[gid] = tc; + tc.trackJoin = true; + tc.trackLeave = true; + tc.trackRoles = true; + tc.channel = answer.Result.MentionedChannels[0]; + tc.Guild = gid; + tc.ChannelId = tc.channel.Id; + } + else { + Database.Delete(Configs.TrackChannels[gid]); + Configs.TrackChannels[gid].channel = answer.Result.MentionedChannels[0]; + Configs.TrackChannels[gid].ChannelId = Configs.TrackChannels[gid].channel.Id; + } + Database.Add(Configs.TrackChannels[gid]); - if (answer.Result.MentionedChannels.Count > 0) { - if (Configs.TrackChannels[gid] == null) { - TrackChannel tc = new(); - Configs.TrackChannels[gid] = tc; - tc.trackJoin = true; - tc.trackLeave = true; - tc.trackRoles = true; - tc.channel = answer.Result.MentionedChannels[0]; - tc.Guild = gid; - tc.ChannelId = tc.channel.Id; } - else { - Database.Delete(Configs.TrackChannels[gid]); - Configs.TrackChannels[gid].channel = answer.Result.MentionedChannels[0]; - Configs.TrackChannels[gid].ChannelId = Configs.TrackChannels[gid].channel.Id; + else if (answer.Result.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase)) { + if (Configs.TrackChannels[gid] != null) { + Database.Delete(Configs.TrackChannels[gid]); + Configs.TrackChannels[gid] = null; + } } - Database.Add(Configs.TrackChannels[gid]); + await ctx.Channel.DeleteMessageAsync(prompt); + msg = CreateTrackingInteraction(ctx, null); } - else if (answer.Result.Content.Contains("remove", StringComparison.InvariantCultureIgnoreCase)) { + + // ************************************************************ DefTracking.Remove Tracking ************************************************************************ + else if (cmdId == "idremtrackch") { if (Configs.TrackChannels[gid] != null) { Database.Delete(Configs.TrackChannels[gid]); Configs.TrackChannels[gid] = null; } - } - - await ctx.Channel.DeleteMessageAsync(prompt); - msg = CreateTrackingInteraction(ctx, null); - } - // ************************************************************ DefTracking.Remove Tracking ************************************************************************ - else if (cmdId == "idremtrackch") { - if (Configs.TrackChannels[gid] != null) { - Database.Delete(Configs.TrackChannels[gid]); - Configs.TrackChannels[gid] = null; + msg = CreateTrackingInteraction(ctx, msg); } - msg = CreateTrackingInteraction(ctx, msg); - } - - // ************************************************************ Alter Tracking Join ************************************************************************ - else if (cmdId == "idaltertrackjoin") { - AlterTracking(gid, true, false, false); - msg = CreateTrackingInteraction(ctx, msg); - } + // ************************************************************ Alter Tracking Join ************************************************************************ + else if (cmdId == "idaltertrackjoin") { + AlterTracking(gid, true, false, false); + msg = CreateTrackingInteraction(ctx, msg); + } - // ************************************************************ Alter Tracking Leave ************************************************************************ - else if (cmdId == "idaltertrackleave") { - AlterTracking(gid, false, true, false); - msg = CreateTrackingInteraction(ctx, msg); - } + // ************************************************************ Alter Tracking Leave ************************************************************************ + else if (cmdId == "idaltertrackleave") { + AlterTracking(gid, false, true, false); + msg = CreateTrackingInteraction(ctx, msg); + } - // ************************************************************ Alter Tracking Roles ************************************************************************ - else if (cmdId == "idaltertrackroles") { - AlterTracking(gid, false, false, true); - msg = CreateTrackingInteraction(ctx, msg); - } + // ************************************************************ Alter Tracking Roles ************************************************************************ + else if (cmdId == "idaltertrackroles") { + AlterTracking(gid, false, false, true); + msg = CreateTrackingInteraction(ctx, msg); + } - // ********* Config Spam Protection *********************************************************************** - else if (cmdId == "idfeatrespamprotect" || cmdId == "idfeatrespamprotect0" || cmdId == "idfeatrespamprotect1" || cmdId == "idfeatrespamprotect2") { - SpamProtection sp = Configs.SpamProtections[gid]; - if (sp == null) { - sp = new SpamProtection(gid); - Configs.SpamProtections[gid] = sp; + // ********* Config Spam Protection *********************************************************************** + else if (cmdId == "idfeatrespamprotect" || cmdId == "idfeatrespamprotect0" || cmdId == "idfeatrespamprotect1" || cmdId == "idfeatrespamprotect2") { + SpamProtection sp = Configs.SpamProtections[gid]; + if (sp == null) { + sp = new SpamProtection(gid); + Configs.SpamProtections[gid] = sp; + } + if (cmdId == "idfeatrespamprotect0") sp.protectDiscord = !sp.protectDiscord; + if (cmdId == "idfeatrespamprotect1") sp.protectSteam = !sp.protectSteam; + if (cmdId == "idfeatrespamprotect2") sp.protectEpic = !sp.protectEpic; + Database.Add(sp); + msg = CreateSpamProtectInteraction(ctx, msg); } - if (cmdId == "idfeatrespamprotect0") sp.protectDiscord = !sp.protectDiscord; - if (cmdId == "idfeatrespamprotect1") sp.protectSteam = !sp.protectSteam; - if (cmdId == "idfeatrespamprotect2") sp.protectEpic = !sp.protectEpic; - Database.Add(sp); - msg = CreateSpamProtectInteraction(ctx, msg); - } - else if (cmdId == "idfeatrespamprotectbl") { - msg = CreateSpamBlackListInteraction(ctx, msg); - } - else if (cmdId == "idfeatrespamprotectwl") { - msg = CreateSpamWhiteListInteraction(ctx, msg); - } - else if (cmdId.Length > 21 && cmdId[0..22] == "idfeatrespamprotectadd") { // Ask for the link, clean it up, and add it - await ctx.Channel.DeleteMessageAsync(msg); - bool whitelist = (cmdId == "idfeatrespamprotectaddwl"); - - DiscordMessage prompt = await ctx.Channel.SendMessageAsync($"{ctx.Member.Mention}, type the url that should be {(whitelist ? "white listed" : "considered spam")}"); - var answer = await interact.WaitForMessageAsync((dm) => { - return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); - }, TimeSpan.FromMinutes(2)); - if (string.IsNullOrWhiteSpace(answer.Result.Content) || !answer.Result.Content.Contains('.')) { - await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config timed out")); - return; + else if (cmdId == "idfeatrespamprotectbl") { + msg = CreateSpamBlackListInteraction(ctx, msg); } - - string link = answer.Result.Content.Trim(); - Regex urlparts = new("[0-9a-z\\.\\-_~]+"); - foreach (Match m in urlparts.Matches(link)) { - string url = m.Value.ToLowerInvariant(); - if (!url.Contains('.')) continue; - - int leftmostdot = url.LastIndexOf('.'); - int seconddot = url.LastIndexOf('.', leftmostdot - 1); - if (seconddot != -1) url = url[(seconddot + 1)..].Trim(); - - Database.Add(new SpamLink(gid, url, whitelist)); - bool found = false; - var list = whitelist ? Configs.WhiteListLinks : Configs.SpamLinks; - foreach (var s in list) { - if (s.Equals(url)) { - found = true; - break; - } + else if (cmdId == "idfeatrespamprotectwl") { + msg = CreateSpamWhiteListInteraction(ctx, msg); + } + else if (cmdId.Length > 21 && cmdId[0..22] == "idfeatrespamprotectadd") { // Ask for the link, clean it up, and add it + await ctx.Channel.DeleteMessageAsync(msg); + bool whitelist = (cmdId == "idfeatrespamprotectaddwl"); + + DiscordMessage prompt = await ctx.Channel.SendMessageAsync($"{ctx.Member.Mention}, type the url that should be {(whitelist ? "white listed" : "considered spam")}"); + var answer = await interact.WaitForMessageAsync((dm) => { + return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); + }, TimeSpan.FromMinutes(2)); + if (string.IsNullOrWhiteSpace(answer.Result.Content) || !answer.Result.Content.Contains('.')) { + await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config timed out")); + return; } - if (!found) { - CheckSpam.SpamCheckTimeout = ctx.Member; - if (whitelist) { - Configs.WhiteListLinks[gid].Add(url); - await ctx.Channel.SendMessageAsync("New white list URL added."); - msg = null; + + string link = answer.Result.Content.Trim(); + Regex urlparts = new("[0-9a-z\\.\\-_~]+"); + foreach (Match m in urlparts.Matches(link)) { + string url = m.Value.ToLowerInvariant(); + if (!url.Contains('.')) continue; + + int leftmostdot = url.LastIndexOf('.'); + int seconddot = url.LastIndexOf('.', leftmostdot - 1); + if (seconddot != -1) url = url[(seconddot + 1)..].Trim(); + + Database.Add(new SpamLink(gid, url, whitelist)); + bool found = false; + var list = whitelist ? Configs.WhiteListLinks : Configs.SpamLinks; + foreach (var s in list) { + if (s.Equals(url)) { + found = true; + break; + } } - else { - Configs.SpamLinks[gid].Add(url); - await ctx.Channel.SendMessageAsync("New spam URL added."); - msg = null; + if (!found) { + CheckSpam.SpamCheckTimeout = ctx.Member; + if (whitelist) { + Configs.WhiteListLinks[gid].Add(url); + await ctx.Channel.SendMessageAsync("New white list URL added."); + msg = null; + } + else { + Configs.SpamLinks[gid].Add(url); + await ctx.Channel.SendMessageAsync("New spam URL added."); + msg = null; + } } } + msg = CreateSpamProtectInteraction(ctx, msg); } - msg = CreateSpamProtectInteraction(ctx, msg); - } - else if (cmdId.Length > 27 && cmdId[0..27] == "idfeatrespamprotectremovebl") { - if (int.TryParse(cmdId[27..], out int num)) { - string link = Configs.SpamLinks[gid][num]; - Configs.SpamLinks[gid].RemoveAt(num); - Database.DeleteByKeys(gid, link); + else if (cmdId.Length > 27 && cmdId[0..27] == "idfeatrespamprotectremovebl") { + if (int.TryParse(cmdId[27..], out int num)) { + string link = Configs.SpamLinks[gid][num]; + Configs.SpamLinks[gid].RemoveAt(num); + Database.DeleteByKeys(gid, link); + } + msg = CreateSpamProtectInteraction(ctx, msg); } - msg = CreateSpamProtectInteraction(ctx, msg); - } - else if (cmdId.Length > 27 && cmdId[0..27] == "idfeatrespamprotectremovewl") { - if (int.TryParse(cmdId[27..], out int num)) { - string link = Configs.WhiteListLinks[gid][num]; - Configs.WhiteListLinks[gid].RemoveAt(num); - Database.DeleteByKeys(gid, link); + else if (cmdId.Length > 27 && cmdId[0..27] == "idfeatrespamprotectremovewl") { + if (int.TryParse(cmdId[27..], out int num)) { + string link = Configs.WhiteListLinks[gid][num]; + Configs.WhiteListLinks[gid].RemoveAt(num); + Database.DeleteByKeys(gid, link); + } + msg = CreateSpamProtectInteraction(ctx, msg); + } + else if (cmdId == "idbackspam") { + msg = CreateSpamProtectInteraction(ctx, msg); } - msg = CreateSpamProtectInteraction(ctx, msg); - } - else if (cmdId == "idbackspam") { - msg = CreateSpamProtectInteraction(ctx, msg); - } - // ***************************************************** UNKNOWN *********************************************************************************** - else { - Utils.Log("Unknown interaction result: " + cmdId, ctx.Guild.Name); + // ***************************************************** UNKNOWN *********************************************************************************** + else { + Utils.Log("Unknown interaction result: " + cmdId, ctx.Guild.Name); + } + result = await interact.WaitForButtonAsync(msg, TimeSpan.FromMinutes(2)); + interRes = result.Result; } - result = await interact.WaitForButtonAsync(msg, TimeSpan.FromMinutes(2)); - interRes = result.Result; - } - if (interRes == null) await ctx.Channel.DeleteMessageAsync(msg); // Expired - else await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config completed")); + if (interRes == null) await ctx.Channel.DeleteMessageAsync(msg); // Expired + else await interRes.Interaction.CreateResponseAsync(DSharpPlus.InteractionResponseType.UpdateMessage, new DiscordInteractionResponseBuilder().WithContent("Config completed")); - } - - static string GenerateSetupList(DiscordGuild g, ulong gid) { // list - - string msg = "Setup list for Discord Server " + g.Name + "\n"; - string part = ""; - // Admins ****************************************************** - if (Configs.AdminRoles[gid].Count == 0) msg += "**AdminRoles**: _no roles defined. Owner and roles with Admin flag will be considered bot Admins_\n"; - else { - foreach (var rid in Configs.AdminRoles[gid]) { - DiscordRole r = g.GetRole(rid); - if (r != null) part += r.Name + ", "; - } - if (part.Length == 0) msg += "**AdminRoles**: _no roles defined. Owner and roles with Admin flag will be considered bot Admins_\n"; - else msg += "**AdminRoles**: " + part[0..^2] + "\n"; } - // TrackingChannel ****************************************************** - if (Configs.TrackChannels[gid] == null) msg += "**TrackingChannel**: _no tracking channel defined_\n"; - else { - msg += "**TrackingChannel**: " + Configs.TrackChannels[gid].channel.Mention + " for "; - if (Configs.TrackChannels[gid].trackJoin || Configs.TrackChannels[gid].trackLeave || Configs.TrackChannels[gid].trackRoles) { - if (Configs.TrackChannels[gid].trackJoin) msg += "_Join_ "; - if (Configs.TrackChannels[gid].trackLeave) msg += "_Leave_ "; - if (Configs.TrackChannels[gid].trackRoles) msg += "_Roles_ "; - } - else msg += "nothing"; - msg += "\n"; - } + static string GenerateSetupList(DiscordGuild g, ulong gid) { // list - // SpamProtection ****************************************************** - SpamProtection sp = Configs.SpamProtections[gid]; - if (sp == null) msg += "**Spam Protection**: _not defined (disabled by default)_\n"; - else if (sp.protectDiscord) { - if (sp.protectSteam) { - if (sp.protectEpic) { - msg += "**Spam Protection**: enabled for _Discord_, _Steam_, and _Epic_\n"; - } - else { - msg += "**Spam Protection**: enabled for _Discord_ and _Steam_\n"; + string msg = "Setup list for Discord Server " + g.Name + "\n"; + string part = ""; + // Admins ****************************************************** + if (Configs.AdminRoles[gid].Count == 0) msg += "**AdminRoles**: _no roles defined. Owner and roles with Admin flag will be considered bot Admins_\n"; + else { + foreach (var rid in Configs.AdminRoles[gid]) { + DiscordRole r = g.GetRole(rid); + if (r != null) part += r.Name + ", "; } + if (part.Length == 0) msg += "**AdminRoles**: _no roles defined. Owner and roles with Admin flag will be considered bot Admins_\n"; + else msg += "**AdminRoles**: " + part[0..^2] + "\n"; } + + // TrackingChannel ****************************************************** + if (Configs.TrackChannels[gid] == null) msg += "**TrackingChannel**: _no tracking channel defined_\n"; else { - if (sp.protectEpic) { - msg += "**Spam Protection**: enabled for _Discord_ and _Epic_\n"; - } - else { - msg += "**Spam Protection**: enabled for _Discord_ only\n"; + msg += "**TrackingChannel**: " + Configs.TrackChannels[gid].channel.Mention + " for "; + if (Configs.TrackChannels[gid].trackJoin || Configs.TrackChannels[gid].trackLeave || Configs.TrackChannels[gid].trackRoles) { + if (Configs.TrackChannels[gid].trackJoin) msg += "_Join_ "; + if (Configs.TrackChannels[gid].trackLeave) msg += "_Leave_ "; + if (Configs.TrackChannels[gid].trackRoles) msg += "_Roles_ "; } + else msg += "nothing"; + msg += "\n"; } - } - else { - if (sp.protectSteam) { - if (sp.protectEpic) { - msg += "**Spam Protection**: enabled for _Steam_ and _Epic_\n"; + + // SpamProtection ****************************************************** + SpamProtection sp = Configs.SpamProtections[gid]; + if (sp == null) msg += "**Spam Protection**: _not defined (disabled by default)_\n"; + else if (sp.protectDiscord) { + if (sp.protectSteam) { + if (sp.protectEpic) { + msg += "**Spam Protection**: enabled for _Discord_, _Steam_, and _Epic_\n"; + } + else { + msg += "**Spam Protection**: enabled for _Discord_ and _Steam_\n"; + } } else { - msg += "**Spam Protection**: enabled for _Steam_ only\n"; + if (sp.protectEpic) { + msg += "**Spam Protection**: enabled for _Discord_ and _Epic_\n"; + } + else { + msg += "**Spam Protection**: enabled for _Discord_ only\n"; + } } } else { - if (sp.protectEpic) { - msg += "**Spam Protection**: enabled for _Epic_ only\n"; + if (sp.protectSteam) { + if (sp.protectEpic) { + msg += "**Spam Protection**: enabled for _Steam_ and _Epic_\n"; + } + else { + msg += "**Spam Protection**: enabled for _Steam_ only\n"; + } } else { - msg += "**Spam Protection**: _disabled_\n"; + if (sp.protectEpic) { + msg += "**Spam Protection**: enabled for _Epic_ only\n"; + } + else { + msg += "**Spam Protection**: _disabled_\n"; + } } } - } - if (Configs.SpamLinks.ContainsKey(gid) && Configs.SpamLinks[gid].Count > 0) { - msg += "**Specific spam links**: "; - bool first = true; - foreach (string sl in Configs.SpamLinks[gid]) { - if (!first) { - msg += ", "; - first = false; + if (Configs.SpamLinks.ContainsKey(gid) && Configs.SpamLinks[gid].Count > 0) { + msg += "**Specific spam links**: "; + bool first = true; + foreach (string sl in Configs.SpamLinks[gid]) { + if (!first) { + msg += ", "; + first = false; + } + msg += sl; } - msg += sl; } + + return msg; } - return msg; - } + public enum SetupCommandItem { + [ChoiceName("Show")] Show = 0, + [ChoiceName("List")] List = 1, + [ChoiceName("Save")] Save = 2, + [ChoiceName("Admins")] Admins = 3 + } - public enum SetupCommandItem { - [ChoiceName("Show")] Show = 0, - [ChoiceName("List")] List = 1, - [ChoiceName("Save")] Save = 2, - [ChoiceName("Admins")] Admins = 3 - } + private static void AlterTracking(ulong gid, bool j, bool l, bool r) { + TrackChannel tc = Configs.TrackChannels[gid]; + if (j) tc.trackJoin = !tc.trackJoin; + if (l) tc.trackLeave = !tc.trackLeave; + if (r) tc.trackRoles = !tc.trackRoles; + Database.Update(tc); + } - private static void AlterTracking(ulong gid, bool j, bool l, bool r) { - TrackChannel tc = Configs.TrackChannels[gid]; - if (j) tc.trackJoin = !tc.trackJoin; - if (l) tc.trackLeave = !tc.trackLeave; - if (r) tc.trackRoles = !tc.trackRoles; - Database.Update(tc); - } - - private void CreateMainConfigPage(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + private void CreateMainConfigPage(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**"; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - var builder = new DiscordInteractionResponseBuilder(); - builder.AddEmbed(eb.Build()); - - //- Set tracking - //- Set Admins - //- Spam Protection - SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; - bool spdisabled = sp == null || (!sp.protectDiscord && !sp.protectSteam && !sp.protectEpic); - List actions = new() { + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**"; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + var builder = new DiscordInteractionResponseBuilder(); + builder.AddEmbed(eb.Build()); + + //- Set tracking + //- Set Admins + //- Spam Protection + SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; + bool spdisabled = sp == null || (!sp.protectDiscord && !sp.protectSteam && !sp.protectEpic); + List actions = new() { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "iddefineadmins", "Define Admins", false, er), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "iddefinetracking", "Define Tracking channel", false, er), new DiscordButtonComponent( spdisabled ? DSharpPlus.ButtonStyle.Secondary : DSharpPlus.ButtonStyle.Primary, "idfeatrespamprotect", "Spam Protection", false, er) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - //-Exit - builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec)); + //-Exit + builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec)); - ctx.CreateResponseAsync(builder); - } - - private DiscordMessage FollowMainConfigPage(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + ctx.CreateResponseAsync(builder); + } - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**"; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); - - //- Set tracking - //- Set Admins - //- Spam Protection - SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; - bool spdisabled = sp == null || (!sp.protectDiscord && !sp.protectSteam && !sp.protectEpic); - List actions = new() { + private DiscordMessage FollowMainConfigPage(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**"; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); + + //- Set tracking + //- Set Admins + //- Spam Protection + SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; + bool spdisabled = sp == null || (!sp.protectDiscord && !sp.protectSteam && !sp.protectEpic); + List actions = new() { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "iddefineadmins", "Define Admins", false, er), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "iddefinetracking", "Define Tracking channel", false, er), new DiscordButtonComponent(spdisabled ? DSharpPlus.ButtonStyle.Secondary : DSharpPlus.ButtonStyle.Primary, "idfeatrespamprotect", "Spam Protection", false, er) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - //-Exit - builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec)); + //-Exit + builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec)); - return ctx.Channel.SendMessageAsync(builder).Result; - } + return ctx.Channel.SendMessageAsync(builder).Result; + } - private DiscordMessage CreateAdminsInteraction(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + private DiscordMessage CreateAdminsInteraction(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration - Admin roles" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - string desc = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n\n" + - "Current server roles that are considered bot administrators:\n"; - - // List admin roles - if (Configs.AdminRoles[ctx.Guild.Id].Count == 0) desc += "_**No admin roles defined.** Owner and server Admins will be used_"; - else { - List roles = Configs.AdminRoles[ctx.Guild.Id]; - bool one = false; - foreach (ulong role in roles) { - DiscordRole dr = ctx.Guild.GetRole(role); - if (dr != null) { - desc += dr.Mention + ", "; - one = true; + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration - Admin roles" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + string desc = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n\n" + + "Current server roles that are considered bot administrators:\n"; + + // List admin roles + if (Configs.AdminRoles[ctx.Guild.Id].Count == 0) desc += "_**No admin roles defined.** Owner and server Admins will be used_"; + else { + List roles = Configs.AdminRoles[ctx.Guild.Id]; + bool one = false; + foreach (ulong role in roles) { + DiscordRole dr = ctx.Guild.GetRole(role); + if (dr != null) { + desc += dr.Mention + ", "; + one = true; + } } + if (one) desc = desc[0..^2]; + else desc += "_**No admin roles defined.** Owner and server Admins will be used_"; } - if (one) desc = desc[0..^2]; - else desc += "_**No admin roles defined.** Owner and server Admins will be used_"; - } - eb.Description = desc; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); - - // - Define roles - List actions = new(); - builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idroleadd", "Add roles", false, ok)); - // - Remove roles - int num = 0; - int cols = 0; - foreach(ulong rid in Configs.AdminRoles[ctx.Guild.Id]) { - DiscordRole role = ctx.Guild.GetRole(rid); - if (role == null) { - Database.DeleteByKeys(ctx.Guild.Id, rid); - continue; - } - actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idrolerem" + num, "Remove " + role.Name, false, ko)); - num++; - cols++; - if (cols == 5) { - cols = 0; - builder.AddComponents(actions); - actions = new List(); + eb.Description = desc; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); + + // - Define roles + List actions = new(); + builder.AddComponents(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idroleadd", "Add roles", false, ok)); + // - Remove roles + int num = 0; + int cols = 0; + foreach (ulong rid in Configs.AdminRoles[ctx.Guild.Id]) { + DiscordRole role = ctx.Guild.GetRole(rid); + if (role == null) { + Database.DeleteByKeys(ctx.Guild.Id, rid); + continue; + } + actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idrolerem" + num, "Remove " + role.Name, false, ko)); + num++; + cols++; + if (cols == 5) { + cols = 0; + builder.AddComponents(actions); + actions = new List(); + } } - } - if (cols > 0) builder.AddComponents(actions); + if (cols > 0) builder.AddComponents(actions); - // - Exit - // - Back - actions = new List { + // - Exit + // - Back + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idback", "Back", false, el) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - return ctx.Channel.SendMessageAsync(builder).Result; - } + return ctx.Channel.SendMessageAsync(builder).Result; + } - private DiscordMessage CreateTrackingInteraction(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + private DiscordMessage CreateTrackingInteraction(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); - TrackChannel tc = Configs.TrackChannels[ctx.Guild.Id]; + TrackChannel tc = Configs.TrackChannels[ctx.Guild.Id]; - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration - Tracking channel" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - string desc = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n\n"; - if (tc == null) desc += "_**No tracking channel defined.**_"; - else { - if (tc.channel == null) desc += "_**No tracking channel defined.**_"; - else desc += "_**Tracking channel:** " + tc.channel.Mention + "_"; - } - eb.Description = desc; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration - Tracking channel" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + string desc = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n\n"; + if (tc == null) desc += "_**No tracking channel defined.**_"; + else { + if (tc.channel == null) desc += "_**No tracking channel defined.**_"; + else desc += "_**Tracking channel:** " + tc.channel.Mention + "_"; + } + eb.Description = desc; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - List actions; - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); + List actions; + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); - // - Change channel - actions = new List { + // - Change channel + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idchangetrackch", "Change channel", false, ok) }; - if (Configs.TrackChannels[ctx.Guild.Id] != null) - actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idremtrackch", "Remove channel", false, ko)); - builder.AddComponents(actions); - - // - Actions to track - if (tc != null) { - actions = new List(); - if (tc.trackJoin) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackjoin", "Track Joint", false, ey)); - else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackjoin", "Track Joint", false, en)); - if (tc.trackLeave) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackleave", "Track Leave", false, ey)); - else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackleave", "Track Leave", false, en)); - if (tc.trackRoles) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackroles", "Track Roles", false, ey)); - else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackroles", "Track Roles", false, en)); + if (Configs.TrackChannels[ctx.Guild.Id] != null) + actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idremtrackch", "Remove channel", false, ko)); builder.AddComponents(actions); - } - // - Exit - // - Back - actions = new List { + // - Actions to track + if (tc != null) { + actions = new List(); + if (tc.trackJoin) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackjoin", "Track Joint", false, ey)); + else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackjoin", "Track Joint", false, en)); + if (tc.trackLeave) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackleave", "Track Leave", false, ey)); + else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackleave", "Track Leave", false, en)); + if (tc.trackRoles) actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Primary, "idaltertrackroles", "Track Roles", false, ey)); + else actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idaltertrackroles", "Track Roles", false, en)); + builder.AddComponents(actions); + } + + // - Exit + // - Back + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idback", "Back", false, el) }; - builder.AddComponents(actions); - - return ctx.Channel.SendMessageAsync(builder).Result; - } + builder.AddComponents(actions); - private DiscordMessage CreateSpamProtectInteraction(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + return ctx.Channel.SendMessageAsync(builder).Result; + } - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration - Spam Protection" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; - bool edisc = sp != null && sp.protectDiscord; - bool esteam = sp != null && sp.protectSteam; - bool eepic = sp != null && sp.protectEpic; - eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + - "The **Spam Protection** is a feature of the bot used to watch all posts contain links.\n" + - "If the link is a counterfait Discord (or Steam, or Epic) link (usually a false free nitro,\n" + - "then the link will be immediately removed.\n\n**Spam Protection** for\n"; - eb.Description += "**Discord Nitro** feature is " + (edisc ? "_Enabled_" : "_Disabled_") + " (_recommended!_)\n"; - eb.Description += "**Steam** feature is " + (esteam ? "_Enabled_" : "_Disabled_") + "\n"; - eb.Description += "**Epic Game Store** feature is " + (eepic ? "_Enabled_" : "_Disabled_") + "\n"; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - List actions; - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); - - actions = new List { + private DiscordMessage CreateSpamProtectInteraction(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration - Spam Protection" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; + bool edisc = sp != null && sp.protectDiscord; + bool esteam = sp != null && sp.protectSteam; + bool eepic = sp != null && sp.protectEpic; + eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + + "The **Spam Protection** is a feature of the bot used to watch all posts contain links.\n" + + "If the link is a counterfait Discord (or Steam, or Epic) link (usually a false free nitro,\n" + + "then the link will be immediately removed.\n\n**Spam Protection** for\n"; + eb.Description += "**Discord Nitro** feature is " + (edisc ? "_Enabled_" : "_Disabled_") + " (_recommended!_)\n"; + eb.Description += "**Steam** feature is " + (esteam ? "_Enabled_" : "_Disabled_") + "\n"; + eb.Description += "**Epic Game Store** feature is " + (eepic ? "_Enabled_" : "_Disabled_") + "\n"; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + List actions; + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); + + actions = new List { new DiscordButtonComponent(edisc ? DSharpPlus.ButtonStyle.Success : DSharpPlus.ButtonStyle.Danger, "idfeatrespamprotect0", "Discord Nitro", false, edisc ? ey : en), new DiscordButtonComponent(esteam ? DSharpPlus.ButtonStyle.Success : DSharpPlus.ButtonStyle.Danger, "idfeatrespamprotect1", "Steam", false, esteam ? ey : en), new DiscordButtonComponent(eepic ? DSharpPlus.ButtonStyle.Success : DSharpPlus.ButtonStyle.Danger, "idfeatrespamprotect2", "Epic", false, eepic ? ey : en) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - actions = new List { + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, "idfeatrespamprotectbl", "Manage Balck List", false, er), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, "idfeatrespamprotectwl", "Manage White List", false, er) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - // - Exit - // - Back - actions = new List { + // - Exit + // - Back + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idback", "Back to Main", false, el) }; - builder.AddComponents(actions); - - return ctx.Channel.SendMessageAsync(builder).Result; - } + builder.AddComponents(actions); - private DiscordMessage CreateSpamWhiteListInteraction(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + return ctx.Channel.SendMessageAsync(builder).Result; + } - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration - Spam Protection" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; - bool edisc = sp != null && sp.protectDiscord; - bool esteam = sp != null && sp.protectSteam; - bool eepic = sp != null && sp.protectEpic; - eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + - "White List of links for the **Spam Protection**, these links will always be allowed.\n" + - "Add with the button a link that will always be accepted in all posted messages.\n" + - "Click on an existing link button to remove it from the white list"; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - List actions; - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); - - actions = new List { + private DiscordMessage CreateSpamWhiteListInteraction(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration - Spam Protection" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + + "White List of links for the **Spam Protection**, these links will always be allowed.\n" + + "Add with the button a link that will always be accepted in all posted messages.\n" + + "Click on an existing link button to remove it from the white list"; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + List actions; + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); + + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, "idfeatrespamprotectaddwl", "Add custom non spam url", false, ok) }; - builder.AddComponents(actions); - - // List all custom spam links - int counter = 0; - actions = new List(); - foreach (string sl in Configs.WhiteListLinks[ctx.Guild.Id]) { - actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, $"idfeatrespamprotectremovewl{counter}", sl, false, ko)); - counter++; - if (counter == 4) { - counter = 0; - builder.AddComponents(actions); - actions = new List(); + builder.AddComponents(actions); + + // List all custom spam links + int counter = 0; + actions = new List(); + foreach (string sl in Configs.WhiteListLinks[ctx.Guild.Id]) { + actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, $"idfeatrespamprotectremovewl{counter}", sl, false, ko)); + counter++; + if (counter == 4) { + counter = 0; + builder.AddComponents(actions); + actions = new List(); + } } - } - if (actions.Count > 0) builder.AddComponents(actions); + if (actions.Count > 0) builder.AddComponents(actions); - // - Exit - // - Back - actions = new List { + // - Exit + // - Back + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idback", "Back to Main", false, el), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idbackspam", "Back to Spam Protection", false, el) }; - builder.AddComponents(actions); - - return ctx.Channel.SendMessageAsync(builder).Result; - } + builder.AddComponents(actions); - private DiscordMessage CreateSpamBlackListInteraction(InteractionContext ctx, DiscordMessage prevMsg) { - if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + return ctx.Channel.SendMessageAsync(builder).Result; + } - DiscordEmbedBuilder eb = new() { - Title = "UPBot Configuration - Spam Protection" - }; - eb.WithThumbnail(ctx.Guild.IconUrl); - SpamProtection sp = Configs.SpamProtections[ctx.Guild.Id]; - bool edisc = sp != null && sp.protectDiscord; - bool esteam = sp != null && sp.protectSteam; - bool eepic = sp != null && sp.protectEpic; - eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + - "Black List of links for the **Spam Protection**\n" + - "Add with the button a link that will be banned from all messages posted.\n" + - "Click on an existing link button to remove it from the black list"; - eb.WithImageUrl(ctx.Guild.BannerUrl); - eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); - - List actions; - var builder = new DiscordMessageBuilder(); - builder.AddEmbed(eb.Build()); - - actions = new List { + private DiscordMessage CreateSpamBlackListInteraction(InteractionContext ctx, DiscordMessage prevMsg) { + if (prevMsg != null) ctx.Channel.DeleteMessageAsync(prevMsg).Wait(); + + DiscordEmbedBuilder eb = new() { + Title = "UPBot Configuration - Spam Protection" + }; + eb.WithThumbnail(ctx.Guild.IconUrl); + eb.Description = "Configuration of the UP Bot for the Discord Server **" + ctx.Guild.Name + "**\n\n" + + "Black List of links for the **Spam Protection**\n" + + "Add with the button a link that will be banned from all messages posted.\n" + + "Click on an existing link button to remove it from the black list"; + eb.WithImageUrl(ctx.Guild.BannerUrl); + eb.WithFooter("Member that started the configuration is: " + ctx.Member.DisplayName, ctx.Member.AvatarUrl); + + List actions; + var builder = new DiscordMessageBuilder(); + builder.AddEmbed(eb.Build()); + + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, "idfeatrespamprotectaddbl", "Add custom spam url", false, ok) }; - builder.AddComponents(actions); - - // List all custom spam links - int counter = 0; - actions = new List(); - foreach (string sl in Configs.SpamLinks[ctx.Guild.Id]) { - actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, $"idfeatrespamprotectremovebl{counter}", sl, false, ko)); - counter++; - if (counter == 4) { - counter = 0; - builder.AddComponents(actions); - actions = new List(); + builder.AddComponents(actions); + + // List all custom spam links + int counter = 0; + actions = new List(); + foreach (string sl in Configs.SpamLinks[ctx.Guild.Id]) { + actions.Add(new DiscordButtonComponent(DSharpPlus.ButtonStyle.Success, $"idfeatrespamprotectremovebl{counter}", sl, false, ko)); + counter++; + if (counter == 4) { + counter = 0; + builder.AddComponents(actions); + actions = new List(); + } } - } - if (actions.Count > 0) builder.AddComponents(actions); + if (actions.Count > 0) builder.AddComponents(actions); - // - Exit - // - Back - actions = new List { + // - Exit + // - Back + actions = new List { new DiscordButtonComponent(DSharpPlus.ButtonStyle.Danger, "idexitconfig", "Exit", false, ec), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idback", "Back to Main", false, el), new DiscordButtonComponent(DSharpPlus.ButtonStyle.Secondary, "idbackspam", "Back to Spam Protection", false, el) }; - builder.AddComponents(actions); + builder.AddComponents(actions); - return ctx.Channel.SendMessageAsync(builder).Result; + return ctx.Channel.SendMessageAsync(builder).Result; + } } -} +} \ No newline at end of file diff --git a/UPBot Code/Commands/Tag.cs b/UPBot Code/Commands/Tag.cs index 75e4b0f..6542205 100644 --- a/UPBot Code/Commands/Tag.cs +++ b/UPBot Code/Commands/Tag.cs @@ -4,191 +4,153 @@ using DSharpPlus.Entities; using DSharpPlus.Interactivity.Extensions; -/// -/// Command that allows helpers, admins, etc. Add more information in "Help Language" script. -/// Author: J0nathan550, CPU -/// -public class SlashTags : ApplicationCommandModule -{ +namespace UPBot { + /// + /// Command that allows helpers, admins, etc. Add more information in "Help Language" script. + /// Author: J0nathan550, CPU + /// + public class SlashTags : ApplicationCommandModule { [SlashCommand("tag", "Show the contents of a specific tag (shows all the tags in case no tag is specified)")] - public async Task TagCommand(InteractionContext ctx, [Option("tagname", "Tag to be shown")] string tagname = null) - { - Utils.LogUserCommand(ctx); - if (tagname != null) - { - try - { - TagBase tag = FindTag(ctx.Guild.Id, tagname.Trim(), true); - //DiscordEmbedBuilder embed = new(); - var builder = new DiscordEmbedBuilder(); - if (tag == null) - { - await ctx.CreateResponseAsync(builder.WithDescription($"{tagname} tag does not exist."), true); - return; - } - if (tag.ColorOfTheme == discordColors.Length) - { - int randomnumber = rand.Next(0, discordColors.Length); - builder.Color = discordColors[randomnumber]; - } - else - { - builder.Color = discordColors[tag.ColorOfTheme]; - } - builder.Timestamp = tag.timeOfCreation; - if (tag.thumbnailLink != null) - { - //builder.Thumbnail.Url = tag.thumbnailLink; - builder.Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail - { - Url = $"{tag.thumbnailLink}" - }; - } - if (tag.imageLink != null) - { - builder.ImageUrl = tag.imageLink; - } - else { } - if (tag != null) - { - builder.Title = tag.Topic; - if (tag.Author == "" || tag.AuthorIcon == "") - { - builder.Author = new DiscordEmbedBuilder.EmbedAuthor - { - Name = "Unknown", - IconUrl = null - }; - } - else - { - builder.Author = new DiscordEmbedBuilder.EmbedAuthor - { - Name = tag.Author, - IconUrl = tag.AuthorIcon - }; - } - string descr = ""; - if (tag.Alias3 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Aliases: {CleanName(tag.Alias1)}, {CleanName(tag.Alias2)}, {CleanName(tag.Alias3)}" }; - else if (tag.Alias2 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Aliases: {CleanName(tag.Alias1)}, {CleanName(tag.Alias2)}" }; - else if (tag.Alias1 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Alias: {CleanName(tag.Alias1)}" }; - descr += tag.Information; - await ctx.CreateResponseAsync(builder.WithDescription(descr)); - } - else - { - await ctx.CreateResponseAsync(builder.WithDescription($"{tagname} tag does not exist."), true); - } + public async Task TagCommand(InteractionContext ctx, [Option("tagname", "Tag to be shown")] string tagname = null) { + Utils.LogUserCommand(ctx); + if (tagname != null) { + try { + TagBase tag = FindTag(ctx.Guild.Id, tagname.Trim(), true); + //DiscordEmbedBuilder embed = new(); + var builder = new DiscordEmbedBuilder(); + if (tag == null) { + await ctx.CreateResponseAsync(builder.WithDescription($"{tagname} tag does not exist."), true); + return; + } + if (tag.ColorOfTheme == discordColors.Length) { + int randomnumber = rand.Next(0, discordColors.Length); + builder.Color = discordColors[randomnumber]; + } + else { + builder.Color = discordColors[tag.ColorOfTheme]; + } + builder.Timestamp = tag.timeOfCreation; + if (tag.thumbnailLink != null) { + //builder.Thumbnail.Url = tag.thumbnailLink; + builder.Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail { + Url = $"{tag.thumbnailLink}" + }; + } + if (tag.imageLink != null) { + builder.ImageUrl = tag.imageLink; + } + else { } + if (tag != null) { + builder.Title = tag.Topic; + if (tag.Author == "" || tag.AuthorIcon == "") { + builder.Author = new DiscordEmbedBuilder.EmbedAuthor { + Name = "Unknown", + IconUrl = null + }; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Tag", ex)); + else { + builder.Author = new DiscordEmbedBuilder.EmbedAuthor { + Name = tag.Author, + IconUrl = tag.AuthorIcon + }; } + string descr = ""; + if (tag.Alias3 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Aliases: {CleanName(tag.Alias1)}, {CleanName(tag.Alias2)}, {CleanName(tag.Alias3)}" }; + else if (tag.Alias2 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Aliases: {CleanName(tag.Alias1)}, {CleanName(tag.Alias2)}" }; + else if (tag.Alias1 != null) builder.Footer = new DiscordEmbedBuilder.EmbedFooter { Text = $"Alias: {CleanName(tag.Alias1)}" }; + descr += tag.Information; + await ctx.CreateResponseAsync(builder.WithDescription(descr)); + } + else { + await ctx.CreateResponseAsync(builder.WithDescription($"{tagname} tag does not exist."), true); + } + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Tag", ex)); } - else - { - try - { - DiscordEmbedBuilder embed = new(); - string result = ""; - if (Configs.Tags[ctx.Guild.Id].Count == 0) - { - result = "No tags are defined. "; - } - else - { - int count = 0; - foreach (TagBase tag in Configs.Tags[ctx.Guild.Id]) - { - count++; - result += $"**{CleanName(tag.Topic)}**"; - if (tag.Alias3 != null) result += $"Aliases: _**{CleanName(tag.Alias1)}**_, _**{CleanName(tag.Alias2)}**_, _**{CleanName(tag.Alias3)}**_"; - else if (tag.Alias2 != null) result += $"Aliases: _**{CleanName(tag.Alias1)}**_, _**{CleanName(tag.Alias2)}**_"; - else if (tag.Alias1 != null) result += $"Alias: _**{CleanName(tag.Alias1)}**_"; - if (count < Configs.Tags[ctx.Guild.Id].Count - 1) result += ", \n"; - else result += "."; - } - count = 0; - } - embed.Title = "List of tags"; - embed.Color = DiscordColor.Blurple; - embed.Description = result[0..^2]; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagList", ex)); + } + else { + try { + DiscordEmbedBuilder embed = new(); + string result = ""; + if (Configs.Tags[ctx.Guild.Id].Count == 0) { + result = "No tags are defined. "; + } + else { + int count = 0; + foreach (TagBase tag in Configs.Tags[ctx.Guild.Id]) { + count++; + result += $"**{CleanName(tag.Topic)}**"; + if (tag.Alias3 != null) result += $"Aliases: _**{CleanName(tag.Alias1)}**_, _**{CleanName(tag.Alias2)}**_, _**{CleanName(tag.Alias3)}**_"; + else if (tag.Alias2 != null) result += $"Aliases: _**{CleanName(tag.Alias1)}**_, _**{CleanName(tag.Alias2)}**_"; + else if (tag.Alias1 != null) result += $"Alias: _**{CleanName(tag.Alias1)}**_"; + if (count < Configs.Tags[ctx.Guild.Id].Count - 1) result += ", \n"; + else result += "."; } + count = 0; + } + embed.Title = "List of tags"; + embed.Color = DiscordColor.Blurple; + embed.Description = result[0..^2]; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagList", ex)); } + } } - static string CleanName(string name) - { - return name.Replace("*", "\\*").Replace("_", "\\_").Replace("`", "\\`"); + static string CleanName(string name) { + return name.Replace("*", "\\*").Replace("_", "\\_").Replace("`", "\\`"); } - public static TagBase FindTag(ulong gid, string name, bool getClosest) - { - foreach (TagBase tag in Configs.Tags[gid]) - { - if (name.Equals(tag.Topic, StringComparison.InvariantCultureIgnoreCase) || - name.Equals(tag.Alias1, StringComparison.InvariantCultureIgnoreCase) || - name.Equals(tag.Alias2, StringComparison.InvariantCultureIgnoreCase) || - name.Equals(tag.Alias3, StringComparison.InvariantCultureIgnoreCase)) - { - return tag; - } + public static TagBase FindTag(ulong gid, string name, bool getClosest) { + foreach (TagBase tag in Configs.Tags[gid]) { + if (name.Equals(tag.Topic, StringComparison.InvariantCultureIgnoreCase) || + name.Equals(tag.Alias1, StringComparison.InvariantCultureIgnoreCase) || + name.Equals(tag.Alias2, StringComparison.InvariantCultureIgnoreCase) || + name.Equals(tag.Alias3, StringComparison.InvariantCultureIgnoreCase)) { + return tag; } - if (getClosest) - { - // Try to find the closest one - - int min = int.MaxValue; - TagBase res = null; - foreach (TagBase tag in Configs.Tags[gid]) - { - int dist = StringDistance.Distance(name, tag.Topic); - if (min > dist) - { - min = dist; - res = tag; - } - if (tag.Alias1 != null) - { - dist = StringDistance.Distance(name, tag.Alias1); - if (min > dist) - { - min = dist; - res = tag; - } - } - if (tag.Alias2 != null) - { - dist = StringDistance.Distance(name, tag.Alias2); - if (min > dist) - { - min = dist; - res = tag; - } - } - if (tag.Alias3 != null) - { - dist = StringDistance.Distance(name, tag.Alias3); - if (min > dist) - { - min = dist; - res = tag; - } - } + } + if (getClosest) { + // Try to find the closest one + + int min = int.MaxValue; + TagBase res = null; + foreach (TagBase tag in Configs.Tags[gid]) { + int dist = StringDistance.Distance(name, tag.Topic); + if (min > dist) { + min = dist; + res = tag; + } + if (tag.Alias1 != null) { + dist = StringDistance.Distance(name, tag.Alias1); + if (min > dist) { + min = dist; + res = tag; } - if (min < 100) - { - return res; + } + if (tag.Alias2 != null) { + dist = StringDistance.Distance(name, tag.Alias2); + if (min > dist) { + min = dist; + res = tag; } + } + if (tag.Alias3 != null) { + dist = StringDistance.Distance(name, tag.Alias3); + if (min > dist) { + min = dist; + res = tag; + } + } + } + if (min < 100) { + return res; } + } - return null; + return null; } readonly Random rand = new(); @@ -216,10 +178,9 @@ public static TagBase FindTag(ulong gid, string name, bool getClosest) DiscordColor.Teal, DiscordColor.Yellow }; -} + } -public enum TagColorValue -{ + public enum TagColorValue { [ChoiceName("Aquamarine")] Aquamarine = 0, [ChoiceName("Azure")] Azure = 1, [ChoiceName("Blurple")] Blurple = 2, @@ -263,580 +224,497 @@ public enum TagColorValue // [ChoiceName("Violet,")] Violet = 38, // [ChoiceName("Wheat")] Wheat = 39, // [ChoiceName("White")] White = 41, -} + } -[SlashCommandGroup("tags", "Define and manage your tags")] -public class SlashTagsEdit : ApplicationCommandModule -{ + [SlashCommandGroup("tags", "Define and manage your tags")] + public class SlashTagsEdit : ApplicationCommandModule { [SlashCommand("addtag", "Adds a new tag")] - public async Task TagAddCommand(InteractionContext ctx, [Option("tagname", "Tag to be added")] string tagname) - { - Utils.LogUserCommand(ctx); - - try - { - DiscordEmbedBuilder embed = new(); - tagname = tagname.Trim(); - - foreach (var topics in Configs.Tags[ctx.Guild.Id]) - { - if (tagname.Equals(topics.Topic, StringComparison.InvariantCultureIgnoreCase) || - tagname.Equals(topics.Alias1, StringComparison.InvariantCultureIgnoreCase) || - tagname.Equals(topics.Alias2, StringComparison.InvariantCultureIgnoreCase) || - tagname.Equals(topics.Alias3, StringComparison.InvariantCultureIgnoreCase)) - { - embed.Title = "The Tag exists already!"; - embed.Color = DiscordColor.Red; - embed.Description = ($"You are trying to add Tag {tagname} that already exists!\nIf you want to edit the Tag use: `tagedit ` - to edit"); - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - } - - embed.Title = "Adding a Tag"; - embed.Color = DiscordColor.Green; - embed.Description = $"Type the content of the Tag {tagname}."; + public async Task TagAddCommand(InteractionContext ctx, [Option("tagname", "Tag to be added")] string tagname) { + Utils.LogUserCommand(ctx); + + try { + DiscordEmbedBuilder embed = new(); + tagname = tagname.Trim(); + + foreach (var topics in Configs.Tags[ctx.Guild.Id]) { + if (tagname.Equals(topics.Topic, StringComparison.InvariantCultureIgnoreCase) || + tagname.Equals(topics.Alias1, StringComparison.InvariantCultureIgnoreCase) || + tagname.Equals(topics.Alias2, StringComparison.InvariantCultureIgnoreCase) || + tagname.Equals(topics.Alias3, StringComparison.InvariantCultureIgnoreCase)) { + embed.Title = "The Tag exists already!"; + embed.Color = DiscordColor.Red; + embed.Description = ($"You are trying to add Tag {tagname} that already exists!\nIf you want to edit the Tag use: `tagedit ` - to edit"); embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); - - var interact = ctx.Client.GetInteractivity(); - var answer = await interact.WaitForMessageAsync((dm) => - { - return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); - }, TimeSpan.FromMinutes(5)); - - if (answer.Result == null) - { - embed.Title = "Time expired!"; - embed.Color = DiscordColor.Red; - embed.Description = $"You took too much time to type the tag."; - embed.Timestamp = DateTime.Now; - await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); - return; - } - TagBase tagBase = new(ctx.Guild.Id, tagname, answer.Result.Content, "", "", 22, DateTime.Now, null, null); // creating line inside of database - Database.Add(tagBase); // adding information to base - Configs.Tags[ctx.Guild.Id].Add(tagBase); - - embed.Title = "Tag added"; - embed.Color = DiscordColor.Green; - embed.Description = ($"The topic: {tagname}, has been created"); - embed.Timestamp = DateTime.Now; - await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); + await ctx.CreateResponseAsync(embed, true); + return; + } } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAdd", ex)); + + embed.Title = "Adding a Tag"; + embed.Color = DiscordColor.Green; + embed.Description = $"Type the content of the Tag {tagname}."; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + + var interact = ctx.Client.GetInteractivity(); + var answer = await interact.WaitForMessageAsync((dm) => { + return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); + }, TimeSpan.FromMinutes(5)); + + if (answer.Result == null) { + embed.Title = "Time expired!"; + embed.Color = DiscordColor.Red; + embed.Description = $"You took too much time to type the tag."; + embed.Timestamp = DateTime.Now; + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); + return; } + TagBase tagBase = new(ctx.Guild.Id, tagname, answer.Result.Content, "", "", 22, DateTime.Now, null, null); // creating line inside of database + Database.Add(tagBase); // adding information to base + Configs.Tags[ctx.Guild.Id].Add(tagBase); + + embed.Title = "Tag added"; + embed.Color = DiscordColor.Green; + embed.Description = ($"The topic: {tagname}, has been created"); + embed.Timestamp = DateTime.Now; + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAdd", ex)); + } } [SlashCommand("removetag", "Removes an existing tag")] - public async Task TagRemoveCommand(InteractionContext ctx, [Option("tagname", "Tag to be removed")] string tagname) - { - Utils.LogUserCommand(ctx); - - try - { - DiscordEmbedBuilder embed = new(); - - TagBase toRemove = SlashTags.FindTag(ctx.Guild.Id, tagname, false); - if (toRemove == null) - { - embed.Title = "The Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagname}` does not exist"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - Configs.Tags[ctx.Guild.Id].Remove(toRemove); - Database.DeleteByKeys(ctx.Guild.Id, toRemove); - - embed.Title = "Topic deleted"; - embed.Color = DiscordColor.DarkRed; - embed.Description = ($"Tag `{tagname}` has been deleted by {ctx.Member.DisplayName}"); - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagRemove", ex)); + public async Task TagRemoveCommand(InteractionContext ctx, [Option("tagname", "Tag to be removed")] string tagname) { + Utils.LogUserCommand(ctx); + + try { + DiscordEmbedBuilder embed = new(); + + TagBase toRemove = SlashTags.FindTag(ctx.Guild.Id, tagname, false); + if (toRemove == null) { + embed.Title = "The Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagname}` does not exist"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + Configs.Tags[ctx.Guild.Id].Remove(toRemove); + Database.DeleteByKeys(ctx.Guild.Id, toRemove); + + embed.Title = "Topic deleted"; + embed.Color = DiscordColor.DarkRed; + embed.Description = ($"Tag `{tagname}` has been deleted by {ctx.Member.DisplayName}"); + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagRemove", ex)); + } } [SlashCommand("listtags", "Shows all tags")] - public async Task TagListCommand(InteractionContext ctx) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - string result = ""; - if (Configs.Tags[ctx.Guild.Id].Count == 0) - { - result = "No tags are defined."; - } - else - { - foreach (TagBase tag in Configs.Tags[ctx.Guild.Id]) - { - result += $"**{tag.Topic}**"; - if (tag.Alias3 != null) result += $" (_**{tag.Alias1}**_, _**{tag.Alias2}**_, _**{tag.Alias3}**_)"; - else if (tag.Alias2 != null) result += $" (_**{tag.Alias1}**_, _**{tag.Alias2}**_)"; - else if (tag.Alias1 != null) result += $" (_**{tag.Alias1}**_)"; - result += $",\n"; - } - } - embed.Title = "List of tags"; - embed.Color = DiscordColor.Blurple; - embed.Description = result[0..^2]; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); + public async Task TagListCommand(InteractionContext ctx) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + string result = ""; + if (Configs.Tags[ctx.Guild.Id].Count == 0) { + result = "No tags are defined."; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagList", ex)); + else { + foreach (TagBase tag in Configs.Tags[ctx.Guild.Id]) { + result += $"**{tag.Topic}**"; + if (tag.Alias3 != null) result += $" (_**{tag.Alias1}**_, _**{tag.Alias2}**_, _**{tag.Alias3}**_)"; + else if (tag.Alias2 != null) result += $" (_**{tag.Alias1}**_, _**{tag.Alias2}**_)"; + else if (tag.Alias1 != null) result += $" (_**{tag.Alias1}**_)"; + result += $",\n"; + } } + embed.Title = "List of tags"; + embed.Color = DiscordColor.Blurple; + embed.Description = result[0..^2]; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagList", ex)); + } } [SlashCommand("aliastag", "Define aliases for a tag")] - public async Task TagAliasCommand(InteractionContext ctx, [Option("tagname", "Tag to be aliased")] string tagname, [Option("alias1", "First alias")] string alias1, [Option("alias2", "Second alias")] string alias2 = null, [Option("alias3", "Third alias")] string alias3 = null) - { - Utils.LogUserCommand(ctx); - - try - { - DiscordEmbedBuilder embed = new(); - - // Find it, can be an alias - TagBase toAlias = SlashTags.FindTag(ctx.Guild.Id, tagname, false); - if (toAlias == null) - { - embed.Title = "The Topic does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagname}` does not exist"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - // Check if we do not have the alias already - if (alias1.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias1.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || - alias1.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias1.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase) || - (alias2 != null && (alias2.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias2.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || - alias2.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias2.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase))) || - (alias3 != null && (alias3.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias3.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || - alias3.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias3.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase)))) - { - embed.Title = "Alias already existing"; - embed.Color = DiscordColor.Yellow; - embed.Description = $"Aliases for {toAlias.Topic.ToUpperInvariant()}:\n"; - if (toAlias.Alias3 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_, _**{toAlias.Alias3}**_)"; - else if (toAlias.Alias2 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_)"; - else if (toAlias.Alias1 != null) embed.Description += $" (_**{toAlias.Alias1}**_)"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - - // Find the first empty alias slot - toAlias.Alias1 = alias1; - toAlias.Alias2 = alias2; - toAlias.Alias3 = alias3; - Database.Add(toAlias); - - embed.Title = "Alias accepted"; - embed.Color = DiscordColor.Green; - embed.Description = $"Aliases for {toAlias.Topic.ToUpperInvariant()}:\n"; - if (toAlias.Alias3 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_, _**{toAlias.Alias3}**_)"; - else if (toAlias.Alias2 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_)"; - else if (toAlias.Alias1 != null) embed.Description += $" (_**{toAlias.Alias1}**_)"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); + public async Task TagAliasCommand(InteractionContext ctx, [Option("tagname", "Tag to be aliased")] string tagname, [Option("alias1", "First alias")] string alias1, [Option("alias2", "Second alias")] string alias2 = null, [Option("alias3", "Third alias")] string alias3 = null) { + Utils.LogUserCommand(ctx); + + try { + DiscordEmbedBuilder embed = new(); + + // Find it, can be an alias + TagBase toAlias = SlashTags.FindTag(ctx.Guild.Id, tagname, false); + if (toAlias == null) { + embed.Title = "The Topic does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagname}` does not exist"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAlias", ex)); + // Check if we do not have the alias already + if (alias1.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias1.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || + alias1.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias1.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase) || + (alias2 != null && (alias2.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias2.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || + alias2.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias2.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase))) || + (alias3 != null && (alias3.Equals(toAlias.Topic, StringComparison.InvariantCultureIgnoreCase) || alias3.Equals(toAlias.Alias1, StringComparison.InvariantCultureIgnoreCase) || + alias3.Equals(toAlias.Alias2, StringComparison.InvariantCultureIgnoreCase) || alias3.Equals(toAlias.Alias3, StringComparison.InvariantCultureIgnoreCase)))) { + embed.Title = "Alias already existing"; + embed.Color = DiscordColor.Yellow; + embed.Description = $"Aliases for {toAlias.Topic.ToUpperInvariant()}:\n"; + if (toAlias.Alias3 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_, _**{toAlias.Alias3}**_)"; + else if (toAlias.Alias2 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_)"; + else if (toAlias.Alias1 != null) embed.Description += $" (_**{toAlias.Alias1}**_)"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + + // Find the first empty alias slot + toAlias.Alias1 = alias1; + toAlias.Alias2 = alias2; + toAlias.Alias3 = alias3; + Database.Add(toAlias); + + embed.Title = "Alias accepted"; + embed.Color = DiscordColor.Green; + embed.Description = $"Aliases for {toAlias.Topic.ToUpperInvariant()}:\n"; + if (toAlias.Alias3 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_, _**{toAlias.Alias3}**_)"; + else if (toAlias.Alias2 != null) embed.Description += $" (_**{toAlias.Alias1}**_, _**{toAlias.Alias2}**_)"; + else if (toAlias.Alias1 != null) embed.Description += $" (_**{toAlias.Alias1}**_)"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAlias", ex)); + } } [SlashCommand("edittag", "Edit an existing tag")] - public async Task TagEditCommand(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string tagname) - { - Utils.LogUserCommand(ctx); - - try - { - DiscordEmbedBuilder embed = new(); - - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagname, false); - if (toEdit == null) - { - embed.Title = "The Topic does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagname}` does not exist"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - - embed.Title = $"Editing {tagname}"; - embed.Color = DiscordColor.Purple; - embed.Description = ($"You are editing the {tagname.ToUpperInvariant()}.\nBetter to copy previous text, and edit inside of message."); - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); - - var interact = ctx.Client.GetInteractivity(); - var answer = await interact.WaitForMessageAsync((dm) => - { - return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); - }, TimeSpan.FromMinutes(5)); - - if (answer.Result == null || string.IsNullOrWhiteSpace(answer.Result.Content)) - { - embed.Title = "Time expired!"; - embed.Color = DiscordColor.Red; - embed.Description = ($"You took too much time to answer. :KO:"); - embed.Timestamp = DateTime.Now; - await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); - return; - } - - toEdit.Information = answer.Result.Content; - Database.Add(toEdit); // adding information to base - - embed.Title = "Changes accepted"; - embed.Color = DiscordColor.Green; - embed.Description = $"New information for {tagname.ToUpperInvariant()}, is:\n\n{answer.Result.Content}\n"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); + public async Task TagEditCommand(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string tagname) { + Utils.LogUserCommand(ctx); + + try { + DiscordEmbedBuilder embed = new(); + + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagname, false); + if (toEdit == null) { + embed.Title = "The Topic does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagname}` does not exist"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagEdit", ex)); + + embed.Title = $"Editing {tagname}"; + embed.Color = DiscordColor.Purple; + embed.Description = ($"You are editing the {tagname.ToUpperInvariant()}.\nBetter to copy previous text, and edit inside of message."); + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + + var interact = ctx.Client.GetInteractivity(); + var answer = await interact.WaitForMessageAsync((dm) => { + return (dm.Channel == ctx.Channel && dm.Author.Id == ctx.Member.Id); + }, TimeSpan.FromMinutes(5)); + + if (answer.Result == null || string.IsNullOrWhiteSpace(answer.Result.Content)) { + embed.Title = "Time expired!"; + embed.Color = DiscordColor.Red; + embed.Description = ($"You took too much time to answer. :KO:"); + embed.Timestamp = DateTime.Now; + await ctx.FollowUpAsync(new DiscordFollowupMessageBuilder().AddEmbed(embed)); + return; } + + toEdit.Information = answer.Result.Content; + Database.Add(toEdit); // adding information to base + + embed.Title = "Changes accepted"; + embed.Color = DiscordColor.Green; + embed.Description = $"New information for {tagname.ToUpperInvariant()}, is:\n\n{answer.Result.Content}\n"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagEdit", ex)); + } } [SlashCommand("removealias", "Removes alias from tag")] - public async Task TagRemoveAlias(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string tagName) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - toEdit.Alias1 = null; - toEdit.Alias2 = null; - toEdit.Alias3 = null; - Database.Add(toEdit); // adding information to base - - var builder = new DiscordEmbedBuilder() - { - Title = "Alias Removed!", - Color = DiscordColor.Green, - Description = $"Removed Alias from: **'{tagName}'**!", - Timestamp = DateTime.Now, - }; - await ctx.CreateResponseAsync(builder); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + public async Task TagRemoveAlias(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string tagName) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + toEdit.Alias1 = null; + toEdit.Alias2 = null; + toEdit.Alias3 = null; + Database.Add(toEdit); // adding information to base + + var builder = new DiscordEmbedBuilder() { + Title = "Alias Removed!", + Color = DiscordColor.Green, + Description = $"Removed Alias from: **'{tagName}'**!", + Timestamp = DateTime.Now, + }; + await ctx.CreateResponseAsync(builder); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + } } [SlashCommand("renametag", "Rename a tag")] - public async Task TagRenameCommand(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string oldname, [Option("newname", "The new name for the tag")] string newname) - { - Utils.LogUserCommand(ctx); - - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, oldname, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{oldname}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } + public async Task TagRenameCommand(InteractionContext ctx, [Option("tagname", "Tag to be modified")] string oldname, [Option("newname", "The new name for the tag")] string newname) { + Utils.LogUserCommand(ctx); + + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, oldname, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{oldname}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; + } - toEdit.Topic = newname.Trim(); - Database.Add(toEdit); // adding information to base + toEdit.Topic = newname.Trim(); + Database.Add(toEdit); // adding information to base - embed.Title = "Changes accepted"; - embed.Color = DiscordColor.Green; - embed.Description = $"New name for {oldname.ToUpperInvariant()}, changed to:\n\n{newname}\n"; - embed.Timestamp = DateTime.Now; + embed.Title = "Changes accepted"; + embed.Color = DiscordColor.Green; + embed.Description = $"New name for {oldname.ToUpperInvariant()}, changed to:\n\n{newname}\n"; + embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagRename", ex)); - } + await ctx.CreateResponseAsync(embed); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagRename", ex)); + } } [SlashCommand("addauthor", "Add author to the tag")] - public async Task TagAddAuthor(InteractionContext ctx, [Option("tagname", "Tag to change the author")] string tagName, [Option("authorname", "Pick author of tag")] string authorName) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } + public async Task TagAddAuthor(InteractionContext ctx, [Option("tagname", "Tag to change the author")] string tagName, [Option("authorname", "Pick author of tag")] string authorName) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; + } - toEdit.Author = authorName.Trim(); - toEdit.AuthorIcon = ctx.Member.AvatarUrl; - Database.Add(toEdit); // adding information to base + toEdit.Author = authorName.Trim(); + toEdit.AuthorIcon = ctx.Member.AvatarUrl; + Database.Add(toEdit); // adding information to base - embed.Title = "Changes accepted!"; - embed.Color = DiscordColor.Green; - embed.Description = $"New author of tag: {tagName.ToUpperInvariant()}, is \n\n{authorName}\n"; - embed.Timestamp = DateTime.Now; + embed.Title = "Changes accepted!"; + embed.Color = DiscordColor.Green; + embed.Description = $"New author of tag: {tagName.ToUpperInvariant()}, is \n\n{authorName}\n"; + embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed); + await ctx.CreateResponseAsync(embed); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAddAuthor", ex)); - } + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagAddAuthor", ex)); + } } [SlashCommand("addcolor", "Add color scheme to tag")] - public async Task TagColorPicking(InteractionContext ctx, [Option("tagname", "Tag to set the color")] string tagName, [Option("colorName", "just a comment")] TagColorValue? colorName = null) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - int colorNumber = (int)colorName; - if (colorNumber <= SlashTags.discordColors.Length) - { - toEdit.ColorOfTheme = colorNumber; - Database.Add(toEdit); // adding information to base - - embed.Title = "Changes accepted!"; - embed.Color = DiscordColor.Green; - embed.Description = $"New color for tag: {tagName.ToUpperInvariant()}, is \n{colorName} {SlashTags.discordColors[colorNumber]} - id {colorNumber}."; - if (colorNumber == SlashTags.discordColors.Length) - embed.Description = $"New color for tag: {tagName.ToUpperInvariant()}, is \n_random color_ (id {colorNumber})."; - else - embed.Timestamp = DateTime.Now; - - await ctx.CreateResponseAsync(embed); - } - else - { - embed.Title = "Color id does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"Color id: {colorNumber} does not exist. Pick onve of the dropdown values!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } + public async Task TagColorPicking(InteractionContext ctx, [Option("tagname", "Tag to set the color")] string tagName, [Option("colorName", "just a comment")] TagColorValue? colorName = null) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; + } + int colorNumber = (int)colorName; + if (colorNumber <= SlashTags.discordColors.Length) { + toEdit.ColorOfTheme = colorNumber; + Database.Add(toEdit); // adding information to base + + embed.Title = "Changes accepted!"; + embed.Color = DiscordColor.Green; + embed.Description = $"New color for tag: {tagName.ToUpperInvariant()}, is \n{colorName} {SlashTags.discordColors[colorNumber]} - id {colorNumber}."; + if (colorNumber == SlashTags.discordColors.Length) + embed.Description = $"New color for tag: {tagName.ToUpperInvariant()}, is \n_random color_ (id {colorNumber})."; + else + embed.Timestamp = DateTime.Now; + + await ctx.CreateResponseAsync(embed); } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagColor", ex)); + else { + embed.Title = "Color id does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"Color id: {colorNumber} does not exist. Pick onve of the dropdown values!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagColor", ex)); + } } [SlashCommand("addimage", "Add a image to the tag")] - public async Task TagImagePicking(InteractionContext ctx, [Option("tagName", "Tag to add the thumbnail")] string tagName, [Option("Image", "Link to image")] string imageLink) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - toEdit.imageLink = imageLink; - Database.Add(toEdit); // adding information to base - - var builder = new DiscordEmbedBuilder - { - Title = "Changes accepted!", - Color = DiscordColor.Green, - ImageUrl = toEdit.imageLink, - Description = $"New Image link for tag: {tagName}, is \n{imageLink}.", - Timestamp = DateTime.Now - }; - await ctx.CreateResponseAsync(builder); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagImage", ex)); + public async Task TagImagePicking(InteractionContext ctx, [Option("tagName", "Tag to add the thumbnail")] string tagName, [Option("Image", "Link to image")] string imageLink) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + toEdit.imageLink = imageLink; + Database.Add(toEdit); // adding information to base + + var builder = new DiscordEmbedBuilder { + Title = "Changes accepted!", + Color = DiscordColor.Green, + ImageUrl = toEdit.imageLink, + Description = $"New Image link for tag: {tagName}, is \n{imageLink}.", + Timestamp = DateTime.Now + }; + await ctx.CreateResponseAsync(builder); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagImage", ex)); + } } [SlashCommand("removeimage", "Remove image from the tag")] - public async Task TagImageRemoving(InteractionContext ctx, [Option("tagName", "Tag with thumbnail")] string tagName) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - if (toEdit.thumbnailLink == null || toEdit.thumbnailLink == "") - { - embed.Title = "Tag does not have any Thumbnail!"; - embed.Color = DiscordColor.Red; - embed.Description = $"Tag does not have any Thumbnail!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - toEdit.thumbnailLink = null; - Database.Add(toEdit); // adding information to base - - var builder = new DiscordEmbedBuilder() - { - Title = "Image Removed!", - Color = DiscordColor.Green, - Description = $"Removed Image from: **'{tagName}'**!", - Timestamp = DateTime.Now, - }; - await ctx.CreateResponseAsync(builder); + public async Task TagImageRemoving(InteractionContext ctx, [Option("tagName", "Tag with thumbnail")] string tagName) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagImage", ex)); + if (toEdit.thumbnailLink == null || toEdit.thumbnailLink == "") { + embed.Title = "Tag does not have any Thumbnail!"; + embed.Color = DiscordColor.Red; + embed.Description = $"Tag does not have any Thumbnail!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + toEdit.thumbnailLink = null; + Database.Add(toEdit); // adding information to base + + var builder = new DiscordEmbedBuilder() { + Title = "Image Removed!", + Color = DiscordColor.Green, + Description = $"Removed Image from: **'{tagName}'**!", + Timestamp = DateTime.Now, + }; + await ctx.CreateResponseAsync(builder); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagImage", ex)); + } } [SlashCommand("addthumbnail", "Add a thumbnail image to the tag")] - public async Task TagThumbnailPicking(InteractionContext ctx, [Option("tagname", "Tag to add the thumbnail")] string tagName, [Option("Thumbnail", "Link to image")] string thumbnailLink) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - toEdit.thumbnailLink = thumbnailLink; - Database.Add(toEdit); // adding information to base - - var builder = new DiscordEmbedBuilder - { - Title = "Changes accepted!", - Color = DiscordColor.Green, - Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail - { - Url = $"{thumbnailLink}" - }, - Description = $"New Thumbnail link for tag: {tagName}, is \n{thumbnailLink}.", - Timestamp = DateTime.Now - }; - await ctx.CreateResponseAsync(builder); - } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + public async Task TagThumbnailPicking(InteractionContext ctx, [Option("tagname", "Tag to add the thumbnail")] string tagName, [Option("Thumbnail", "Link to image")] string thumbnailLink) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + toEdit.thumbnailLink = thumbnailLink; + Database.Add(toEdit); // adding information to base + + var builder = new DiscordEmbedBuilder { + Title = "Changes accepted!", + Color = DiscordColor.Green, + Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail { + Url = $"{thumbnailLink}" + }, + Description = $"New Thumbnail link for tag: {tagName}, is \n{thumbnailLink}.", + Timestamp = DateTime.Now + }; + await ctx.CreateResponseAsync(builder); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + } } [SlashCommand("removethumbnail", "Remove the thumbnail image from the tag")] - public async Task TagThumbnailRemoving(InteractionContext ctx, [Option("tagname", "Tag with thumbnail")] string tagName) - { - Utils.LogUserCommand(ctx); - try - { - DiscordEmbedBuilder embed = new(); - TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); - if (toEdit == null) - { - embed.Title = "Tag does not exist!"; - embed.Color = DiscordColor.Red; - embed.Description = $"The tag `{tagName}` does not exist!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - if (toEdit.thumbnailLink == null || toEdit.thumbnailLink == "") - { - embed.Title = "Tag does not have any Thumbnail!"; - embed.Color = DiscordColor.Red; - embed.Description = $"Tag does not have any Thumbnail!"; - embed.Timestamp = DateTime.Now; - await ctx.CreateResponseAsync(embed, true); - return; - } - toEdit.thumbnailLink = null; - Database.Add(toEdit); // adding information to base - - var builder = new DiscordEmbedBuilder() - { - Title = "Thumbnail Removed!", - Color = DiscordColor.Green, - Description = $"Removed Thumbnail from: **'{tagName}'**!", - Timestamp = DateTime.Now, - }; - await ctx.CreateResponseAsync(builder); + public async Task TagThumbnailRemoving(InteractionContext ctx, [Option("tagname", "Tag with thumbnail")] string tagName) { + Utils.LogUserCommand(ctx); + try { + DiscordEmbedBuilder embed = new(); + TagBase toEdit = SlashTags.FindTag(ctx.Guild.Id, tagName, false); + if (toEdit == null) { + embed.Title = "Tag does not exist!"; + embed.Color = DiscordColor.Red; + embed.Description = $"The tag `{tagName}` does not exist!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } - catch (Exception ex) - { - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + if (toEdit.thumbnailLink == null || toEdit.thumbnailLink == "") { + embed.Title = "Tag does not have any Thumbnail!"; + embed.Color = DiscordColor.Red; + embed.Description = $"Tag does not have any Thumbnail!"; + embed.Timestamp = DateTime.Now; + await ctx.CreateResponseAsync(embed, true); + return; } + toEdit.thumbnailLink = null; + Database.Add(toEdit); // adding information to base + + var builder = new DiscordEmbedBuilder() { + Title = "Thumbnail Removed!", + Color = DiscordColor.Green, + Description = $"Removed Thumbnail from: **'{tagName}'**!", + Timestamp = DateTime.Now, + }; + await ctx.CreateResponseAsync(builder); + } catch (Exception ex) { + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "TagThumbnail", ex)); + } } -} + } +} \ No newline at end of file diff --git a/UPBot Code/Commands/Timezone.cs b/UPBot Code/Commands/Timezone.cs index 2db0231..acfe0e8 100644 --- a/UPBot Code/Commands/Timezone.cs +++ b/UPBot Code/Commands/Timezone.cs @@ -10,252 +10,254 @@ /// author: CPU /// +namespace UPBot { -[SlashCommandGroup("tz", "Commands to check timezones")] -public class SlashTimezone : ApplicationCommandModule { - [SlashCommand("whattimeis", "Checks the current local time in a timezone")] - public async Task TZTimeCommand(InteractionContext ctx, [Option("timezone", "Timezone to check the local time")] string tz) { - Utils.LogUserCommand(ctx); + [SlashCommandGroup("tz", "Commands to check timezones")] + public class SlashTimezone : ApplicationCommandModule { + [SlashCommand("whattimeis", "Checks the current local time in a timezone")] + public async Task TZTimeCommand(InteractionContext ctx, [Option("timezone", "Timezone to check the local time")] string tz) { + Utils.LogUserCommand(ctx); - try { - List res = GetTimezone(tz, out TimeZoneInfo tzi); - if (res == null && tzi == null) { - await ctx.CreateResponseAsync($"I cannot find a timezone similar to {tz}.", true); - } - else if (tzi != null) { - DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzi); - await ctx.CreateResponseAsync($"Current time in the timezone is {dest:HH:mm:ss}\n{GetTZName(tzi)}"); - } - else { - string msg = $"Cannot find a timezone for {tz}, best opportunities are:\n"; - foreach (var r in res) { - if (TZConvert.TryGetTimeZoneInfo(r.IanaName, out TimeZoneInfo ttz)) { - msg += "(" + r.Score + ") " + GetTZName(ttz) + "\n"; + try { + List res = GetTimezone(tz, out TimeZoneInfo tzi); + if (res == null && tzi == null) { + await ctx.CreateResponseAsync($"I cannot find a timezone similar to {tz}.", true); + } + else if (tzi != null) { + DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzi); + await ctx.CreateResponseAsync($"Current time in the timezone is {dest:HH:mm:ss}\n{GetTZName(tzi)}"); + } + else { + string msg = $"Cannot find a timezone for {tz}, best opportunities are:\n"; + foreach (var r in res) { + if (TZConvert.TryGetTimeZoneInfo(r.IanaName, out TimeZoneInfo ttz)) { + msg += "(" + r.Score + ") " + GetTZName(ttz) + "\n"; + } } + await ctx.CreateResponseAsync(msg, true); } - await ctx.CreateResponseAsync(msg, true); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatTimeIs", ex), true); } - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatTimeIs", ex), true); } - } - [SlashCommand("whattimeisfor", "Checks the current local time for an user")] - public async Task TZTimeGetCommand(InteractionContext ctx, [Option("user", "The user for the time")] DiscordUser user) { - Utils.LogUserCommand(ctx); + [SlashCommand("whattimeisfor", "Checks the current local time for an user")] + public async Task TZTimeGetCommand(InteractionContext ctx, [Option("user", "The user for the time")] DiscordUser user) { + Utils.LogUserCommand(ctx); - try { - DiscordMember member = await ctx.Guild.GetMemberAsync(user.Id); - Timezone utz = Database.GetByKey(user.Id); - if (utz == null) { - await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is not defined", true); - return; - } + try { + DiscordMember member = await ctx.Guild.GetMemberAsync(user.Id); + Timezone utz = Database.GetByKey(user.Id); + if (utz == null) { + await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is not defined", true); + return; + } + + if (!TZConvert.TryGetTimeZoneInfo(utz.TimeZoneName, out var tzinfo)) { + await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is not clear: {utz.TimeZoneName}", true); + return; + } - if (!TZConvert.TryGetTimeZoneInfo(utz.TimeZoneName, out var tzinfo)) { - await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is not clear: {utz.TimeZoneName}", true); - return; + DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzinfo); + await ctx.CreateResponseAsync($"Current time for user {member.DisplayName} is {dest:HH:mm:ss}\n{GetTZName(tzinfo)}"); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatTimeIsFor", ex), true); } - - DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzinfo); - await ctx.CreateResponseAsync($"Current time for user {member.DisplayName} is {dest:HH:mm:ss}\n{GetTZName(tzinfo)}"); - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "WhatTimeIsFor", ex), true); } - } - [SlashCommand("set", "Set the timezone for a user")] - public async Task TZSetCommand(InteractionContext ctx, [Option("user", "The user to set the timezone")] DiscordUser user, [Option("timezone", "Timezone to check the local time")] string tz) { - try { - DiscordMember member = await ctx.Guild.GetMemberAsync(user.Id); - if (!Configs.HasAdminRole(ctx.Guild.Id, member.Roles, false) && user.Id != ctx.User.Id) { Utils.DefaultNotAllowed(ctx); return; } - Utils.LogUserCommand(ctx); + [SlashCommand("set", "Set the timezone for a user")] + public async Task TZSetCommand(InteractionContext ctx, [Option("user", "The user to set the timezone")] DiscordUser user, [Option("timezone", "Timezone to check the local time")] string tz) { + try { + DiscordMember member = await ctx.Guild.GetMemberAsync(user.Id); + if (!Configs.HasAdminRole(ctx.Guild.Id, member.Roles, false) && user.Id != ctx.User.Id) { Utils.DefaultNotAllowed(ctx); return; } + Utils.LogUserCommand(ctx); - List res = GetTimezone(tz, out TimeZoneInfo tzi); - if (res == null && tzi == null) { - await ctx.CreateResponseAsync($"I cannot find a timezone similar to {tz}.", true); - } - else if (tzi != null) { - DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzi); - string tzid = tzi.Id; - if (TZConvert.TryWindowsToIana(tzid, out string tzname)) tzid = tzname; - Database.Add(new Timezone(user.Id, tzid)); - await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is set to {GetTZName(tzi)}. Current time for they is {dest:HH:mm:ss}"); - } - else { - string msg = $"Cannot find a timezone for {tz}, best opportunities are:\n"; - foreach (var r in res) { - if (TZConvert.TryGetTimeZoneInfo(r.IanaName, out TimeZoneInfo ttz)) { - msg += "(" + r.Score + ") " + ttz.StandardName + " (" + r.IanaName + ") UTC"; - if (ttz.BaseUtcOffset >= TimeSpan.Zero) msg += "+"; else msg += "-"; - msg += Math.Abs(ttz.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(ttz.BaseUtcOffset.Minutes).ToString("00"); - msg += "\n"; - } + List res = GetTimezone(tz, out TimeZoneInfo tzi); + if (res == null && tzi == null) { + await ctx.CreateResponseAsync($"I cannot find a timezone similar to {tz}.", true); } + else if (tzi != null) { + DateTime dest = TimeZoneInfo.ConvertTime(DateTime.Now, tzi); + string tzid = tzi.Id; + if (TZConvert.TryWindowsToIana(tzid, out string tzname)) tzid = tzname; + Database.Add(new Timezone(user.Id, tzid)); + await ctx.CreateResponseAsync($"Timezone for user {member.DisplayName} is set to {GetTZName(tzi)}. Current time for they is {dest:HH:mm:ss}"); + } + else { + string msg = $"Cannot find a timezone for {tz}, best opportunities are:\n"; + foreach (var r in res) { + if (TZConvert.TryGetTimeZoneInfo(r.IanaName, out TimeZoneInfo ttz)) { + msg += "(" + r.Score + ") " + ttz.StandardName + " (" + r.IanaName + ") UTC"; + if (ttz.BaseUtcOffset >= TimeSpan.Zero) msg += "+"; else msg += "-"; + msg += Math.Abs(ttz.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(ttz.BaseUtcOffset.Minutes).ToString("00"); + msg += "\n"; + } + } - await ctx.CreateResponseAsync(msg); + await ctx.CreateResponseAsync(msg); + } + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Set Timezone", ex), true); } - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "Set Timezone", ex), true); } - } - [SlashCommand("list", "List all timezones with how many users are in each one")] - public async Task TZListCommand(InteractionContext ctx) { - try { - string res = "```\n"; - var list = Database.GetAll(); - Dictionary count = new(); - foreach (Timezone t in list) { - if (!count.ContainsKey(t.TimeZoneName)) count[t.TimeZoneName] = 1; - else count[t.TimeZoneName]++; - } - string bads = ""; - int numbads = 0; - foreach (var tzcode in count.Keys) { - if (TZConvert.TryGetTimeZoneInfo(tzcode, out var tzinfo)) { - string tzid = tzinfo.Id; - if (TZConvert.TryWindowsToIana(tzid, out string tzidname)) tzid = tzidname; - string tzname = tzid + " (" + tzinfo.DisplayName + ") UTC"; - if (tzinfo.BaseUtcOffset >= TimeSpan.Zero) tzname += "+"; else tzname += "-"; - tzname += Math.Abs(tzinfo.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(tzinfo.BaseUtcOffset.Minutes).ToString("00"); - res += count[tzcode] + (count[tzcode] == 1 ? " user " : " users ") + tzname + "\n"; + [SlashCommand("list", "List all timezones with how many users are in each one")] + public async Task TZListCommand(InteractionContext ctx) { + try { + string res = "```\n"; + var list = Database.GetAll(); + Dictionary count = new(); + foreach (Timezone t in list) { + if (!count.ContainsKey(t.TimeZoneName)) count[t.TimeZoneName] = 1; + else count[t.TimeZoneName]++; } - else { - bads += tzcode + ", "; - numbads++; + string bads = ""; + int numbads = 0; + foreach (var tzcode in count.Keys) { + if (TZConvert.TryGetTimeZoneInfo(tzcode, out var tzinfo)) { + string tzid = tzinfo.Id; + if (TZConvert.TryWindowsToIana(tzid, out string tzidname)) tzid = tzidname; + string tzname = tzid + " (" + tzinfo.DisplayName + ") UTC"; + if (tzinfo.BaseUtcOffset >= TimeSpan.Zero) tzname += "+"; else tzname += "-"; + tzname += Math.Abs(tzinfo.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(tzinfo.BaseUtcOffset.Minutes).ToString("00"); + res += count[tzcode] + (count[tzcode] == 1 ? " user " : " users ") + tzname + "\n"; + } + else { + bads += tzcode + ", "; + numbads++; + } } + if (numbads > 0) { + res += numbads + " Unknown timezones: " + bads[..^2] + "\n"; + } + res += "```"; + await ctx.CreateResponseAsync(res); + } catch (Exception ex) { + if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out + await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "List Timezones", ex), true); } - if (numbads > 0) { - res += numbads + " Unknown timezones: " + bads[..^2] + "\n"; - } - res += "```"; - await ctx.CreateResponseAsync(res); - } catch (Exception ex) { - if (ex is DSharpPlus.Exceptions.NotFoundException) return; // Timed out - await ctx.CreateResponseAsync(Utils.GenerateErrorAnswer(ctx.Guild.Name, "List Timezones", ex), true); } - } - class RankedTimezone { public string IanaName; public int Score; } - static Dictionary fullTZList; + class RankedTimezone { public string IanaName; public int Score; } + static Dictionary fullTZList; - static string GetTZName(TimeZoneInfo tzinfo) { - string tzid = tzinfo.Id; - if (TZConvert.TryWindowsToIana(tzinfo.Id, out string tzname)) tzid = tzname; - string tzn = tzinfo.StandardName + " / " + tzid + " (UTC"; - if (tzinfo.BaseUtcOffset >= TimeSpan.Zero) tzn += "+"; else tzn += "-"; - tzn += Math.Abs(tzinfo.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(tzinfo.BaseUtcOffset.Minutes).ToString("00") + ")"; - return tzn; - } + static string GetTZName(TimeZoneInfo tzinfo) { + string tzid = tzinfo.Id; + if (TZConvert.TryWindowsToIana(tzinfo.Id, out string tzname)) tzid = tzname; + string tzn = tzinfo.StandardName + " / " + tzid + " (UTC"; + if (tzinfo.BaseUtcOffset >= TimeSpan.Zero) tzn += "+"; else tzn += "-"; + tzn += Math.Abs(tzinfo.BaseUtcOffset.Hours).ToString("00") + ":" + Math.Abs(tzinfo.BaseUtcOffset.Minutes).ToString("00") + ")"; + return tzn; + } - int GetTZScore(string src, string dst) { - if (src.Equals(dst, StringComparison.InvariantCultureIgnoreCase)) return 100; - if (dst.Contains(src, StringComparison.InvariantCultureIgnoreCase)) return (int)(100f * src.Length / dst.Length); + int GetTZScore(string src, string dst) { + if (src.Equals(dst, StringComparison.InvariantCultureIgnoreCase)) return 100; + if (dst.Contains(src, StringComparison.InvariantCultureIgnoreCase)) return (int)(100f * src.Length / dst.Length); - var srcpts = src.ToLowerInvariant().Split(' ', '/', '(', ')', '_'); - var dstpts = dst.ToLowerInvariant().Split(' ', '/', '(', ')', '_'); - int score = 0; - foreach (var d in dstpts) { - if (string.IsNullOrWhiteSpace(d)) continue; - foreach (var s in srcpts) { - if (string.IsNullOrWhiteSpace(s)) continue; - if (d.Equals(s)) score += 12; - else if (s.Equals("est") || s.Equals("east") || s.Equals("eastern")) { - if (d.Equals("e.")) score += 8; - } - else if (s.Equals("west") || s.Equals("western")) { - if (d.Equals("w.")) score += 8; - } - else if (s.Equals("america") || s.Equals("usa")) { - if (d.Equals("us")) score += 6; - } - else { - int min = s.Length; - if (d.Length < min) min = d.Length; - int dist = StringDistance.DLDistance(s, d); - if (dist < min / 5) score += min - dist; + var srcpts = src.ToLowerInvariant().Split(' ', '/', '(', ')', '_'); + var dstpts = dst.ToLowerInvariant().Split(' ', '/', '(', ')', '_'); + int score = 0; + foreach (var d in dstpts) { + if (string.IsNullOrWhiteSpace(d)) continue; + foreach (var s in srcpts) { + if (string.IsNullOrWhiteSpace(s)) continue; + if (d.Equals(s)) score += 12; + else if (s.Equals("est") || s.Equals("east") || s.Equals("eastern")) { + if (d.Equals("e.")) score += 8; + } + else if (s.Equals("west") || s.Equals("western")) { + if (d.Equals("w.")) score += 8; + } + else if (s.Equals("america") || s.Equals("usa")) { + if (d.Equals("us")) score += 6; + } + else { + int min = s.Length; + if (d.Length < min) min = d.Length; + int dist = StringDistance.DLDistance(s, d); + if (dist < min / 5) score += min - dist; + } } } + return (int)(score * 1f / srcpts.Length); } - return (int)(score * 1f / srcpts.Length); - } - List CheckProx(string inp) { - List res = new(); - foreach (string key in fullTZList.Keys) { - int score = GetTZScore(inp, key); - if (score > 8) { - res.Add(new RankedTimezone { IanaName = key, Score = score }); - } - else { - score = GetTZScore(inp, fullTZList[key]); - if (score >= 8) { + List CheckProx(string inp) { + List res = new(); + foreach (string key in fullTZList.Keys) { + int score = GetTZScore(inp, key); + if (score > 8) { res.Add(new RankedTimezone { IanaName = key, Score = score }); } + else { + score = GetTZScore(inp, fullTZList[key]); + if (score >= 8) { + res.Add(new RankedTimezone { IanaName = key, Score = score }); + } + } } - } - res.Sort((a, b) => { return b.Score.CompareTo(a.Score); }); + res.Sort((a, b) => { return b.Score.CompareTo(a.Score); }); - if (res.Count == 0) return null; + if (res.Count == 0) return null; - int val = res[0].Score; - for (int i = res.Count - 1; i > 1; i--) { - if (res[i].Score <= val - 5) res.RemoveAt(i); + int val = res[0].Score; + for (int i = res.Count - 1; i > 1; i--) { + if (res[i].Score <= val - 5) res.RemoveAt(i); + } + return res; } - return res; - } - static void InitTimeZones() { - fullTZList = new Dictionary(); - var work = new Dictionary(); - foreach (var t in TZConvert.KnownIanaTimeZoneNames) - work[t] = t; - foreach (var t in TZConvert.KnownWindowsTimeZoneIds) { - string key = t; - if (TZConvert.TryWindowsToIana(t, out string tzidname)) key = tzidname; - if (!work.ContainsKey(key)) work[key] = t; - else work[key] += " " + t; - } - foreach (var t in TZConvert.KnownRailsTimeZoneNames) { - string key = TZConvert.RailsToIana(t); - if (!work.ContainsKey(key)) work[key] = t; - else work[key] += " " + t; - } + static void InitTimeZones() { + fullTZList = new Dictionary(); + var work = new Dictionary(); + foreach (var t in TZConvert.KnownIanaTimeZoneNames) + work[t] = t; + foreach (var t in TZConvert.KnownWindowsTimeZoneIds) { + string key = t; + if (TZConvert.TryWindowsToIana(t, out string tzidname)) key = tzidname; + if (!work.ContainsKey(key)) work[key] = t; + else work[key] += " " + t; + } + foreach (var t in TZConvert.KnownRailsTimeZoneNames) { + string key = TZConvert.RailsToIana(t); + if (!work.ContainsKey(key)) work[key] = t; + else work[key] += " " + t; + } - foreach (string key in work.Keys) { - string val = work[key]; - string cleaned = ""; - string[] parts = val.Split(' '); - foreach (var part in parts) - if (!cleaned.Contains(part, StringComparison.InvariantCultureIgnoreCase)) cleaned += part + " "; - fullTZList[key] = cleaned.Trim(); + foreach (string key in work.Keys) { + string val = work[key]; + string cleaned = ""; + string[] parts = val.Split(' '); + foreach (var part in parts) + if (!cleaned.Contains(part, StringComparison.InvariantCultureIgnoreCase)) cleaned += part + " "; + fullTZList[key] = cleaned.Trim(); + } } - } - List GetTimezone(string input, out TimeZoneInfo res) { - if (fullTZList == null) InitTimeZones(); - if (TZConvert.TryGetTimeZoneInfo(input, out TimeZoneInfo tz)) { - res = tz; - return null; - } - res = null; - var list = CheckProx(input); - if (list?.Count == 1) { - if (TZConvert.TryGetTimeZoneInfo(list[0].IanaName, out tz)) { + List GetTimezone(string input, out TimeZoneInfo res) { + if (fullTZList == null) InitTimeZones(); + if (TZConvert.TryGetTimeZoneInfo(input, out TimeZoneInfo tz)) { res = tz; return null; } + res = null; + var list = CheckProx(input); + if (list?.Count == 1) { + if (TZConvert.TryGetTimeZoneInfo(list[0].IanaName, out tz)) { + res = tz; + return null; + } + } + return list; } - return list; - } + } } \ No newline at end of file diff --git a/UPBot Code/Config.cs b/UPBot Code/Config.cs index b7c16f0..af1f3e3 100644 --- a/UPBot Code/Config.cs +++ b/UPBot Code/Config.cs @@ -6,222 +6,225 @@ using DSharpPlus.Entities; using DSharpPlus.EventArgs; -public class TempSetRole { - public DiscordRole role; - public CancellationTokenSource cancel; - public ulong user; - internal ulong channel; - internal ulong message; - internal ulong emojiid; - internal string emojiname; - - public TempSetRole(ulong usr, DiscordRole r) { - user = usr; - role = r; - cancel = new CancellationTokenSource(); - channel = 0; - message = 0; - emojiid = 0; - emojiname = null; +namespace UPBot { + public class TempSetRole { + public DiscordRole role; + public CancellationTokenSource cancel; + public ulong user; + internal ulong channel; + internal ulong message; + internal ulong emojiid; + internal string emojiname; + + public TempSetRole(ulong usr, DiscordRole r) { + user = usr; + role = r; + cancel = new CancellationTokenSource(); + channel = 0; + message = 0; + emojiid = 0; + emojiname = null; + } } -} - -/// -/// This command is used to configure the bot, so roles and messages can be set for other servers. -/// author: CPU -/// -public class Configs { - readonly private static Dictionary Guilds = new(); - readonly public static Dictionary TrackChannels = new(); - readonly public static Dictionary> AdminRoles = new(); - readonly public static Dictionary SpamProtections = new(); - readonly public static Dictionary> Tags = new(); - readonly public static Dictionary> SpamLinks = new(); - readonly public static Dictionary> WhiteListLinks = new(); - - readonly public static Dictionary TempRoleSelected = new(); - - public readonly static Regex emjSnowflakeRE = new(@"<:[a-z0-9_]+:([0-9]+)>", RegexOptions.IgnoreCase | RegexOptions.Compiled); - public readonly static Regex roleSnowflakeRR = new("<@[^0-9]+([0-9]*)>", RegexOptions.Compiled); - public readonly static Regex emjUnicodeRE = new(@"[#*0-9]\uFE0F?\u20E3|©\uFE0F?|[®\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA]\uFE0F?|[\u231A\u231B]|[\u2328\u23CF]\uFE0F?|[\u23E9-\u23EC]|[\u23ED-\u23EF]\uFE0F?|\u23F0|[\u23F1\u23F2]\uFE0F?|\u23F3|[\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC]\uFE0F?|[\u25FD\u25FE]|[\u2600-\u2604\u260E\u2611]\uFE0F?|[\u2614\u2615]|\u2618\uFE0F?|\u261D(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642]\uFE0F?|[\u2648-\u2653]|[\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E]\uFE0F?|\u267F|\u2692\uFE0F?|\u2693|[\u2694-\u2697\u2699\u269B\u269C\u26A0]\uFE0F?|\u26A1|\u26A7\uFE0F?|[\u26AA\u26AB]|[\u26B0\u26B1]\uFE0F?|[\u26BD\u26BE\u26C4\u26C5]|\u26C8\uFE0F?|\u26CE|[\u26CF\u26D1\u26D3]\uFE0F?|\u26D4|\u26E9\uFE0F?|\u26EA|[\u26F0\u26F1]\uFE0F?|[\u26F2\u26F3]|\u26F4\uFE0F?|\u26F5|[\u26F7\u26F8]\uFE0F?|\u26F9(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\u26FA\u26FD]|\u2702\uFE0F?|\u2705|[\u2708\u2709]\uFE0F?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|\u270F\uFE0F?|[\u2712\u2714\u2716\u271D\u2721]\uFE0F?|\u2728|[\u2733\u2734\u2744\u2747]\uFE0F?|[\u274C\u274E\u2753-\u2755\u2757]|\u2763\uFE0F?|\u2764(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uFE0F(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?)?|[\u2795-\u2797]|\u27A1\uFE0F?|[\u27B0\u27BF]|[\u2934\u2935\u2B05-\u2B07]\uFE0F?|[\u2B1B\u2B1C\u2B50\u2B55]|[\u3030\u303D\u3297\u3299]\uFE0F?|\uD83C(?:[\uDC04\uDCCF]|[\uDD70\uDD71\uDD7E\uDD7F]\uFE0F?|[\uDD8E\uDD91-\uDD9A]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDE01|\uDE02\uFE0F?|[\uDE1A\uDE2F\uDE32-\uDE36]|\uDE37\uFE0F?|[\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20]|[\uDF21\uDF24-\uDF2C]\uFE0F?|[\uDF2D-\uDF35]|\uDF36\uFE0F?|[\uDF37-\uDF7C]|\uDF7D\uFE0F?|[\uDF7E-\uDF84]|\uDF85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDF86-\uDF93]|[\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F]\uFE0F?|[\uDFA0-\uDFC1]|\uDFC2(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFC5\uDFC6]|\uDFC7(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC8\uDFC9]|\uDFCA(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFCB\uDFCC](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFCD\uDFCE]\uFE0F?|[\uDFCF-\uDFD3]|[\uDFD4-\uDFDF]\uFE0F?|[\uDFE0-\uDFF0]|\uDFF3(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08)|\uFE0F(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?)?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?|[\uDFF5\uDFF7]\uFE0F?|[\uDFF8-\uDFFF])|\uD83D(?:[\uDC00-\uDC07]|\uDC08(?:\u200D\u2B1B)?|[\uDC09-\uDC14]|\uDC15(?:\u200D\uD83E\uDDBA)?|[\uDC16-\uDC3A]|\uDC3B(?:\u200D\u2744\uFE0F?)?|[\uDC3C-\uDC3E]|\uDC3F\uFE0F?|\uDC40|\uDC41(?:\u200D\uD83D\uDDE8\uFE0F?|\uFE0F(?:\u200D\uD83D\uDDE8\uFE0F?)?)?|[\uDC42\uDC43](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC44\uDC45]|[\uDC46-\uDC50](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC51-\uDC65]|[\uDC66\uDC67](?:\uD83C[\uDFFB-\uDFFF])?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC6A|[\uDC6B-\uDC6D](?:\uD83C[\uDFFB-\uDFFF])?|\uDC6E(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDC70\uDC71](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC72(?:\uD83C[\uDFFB-\uDFFF])?|\uDC73(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDC74-\uDC76](?:\uD83C[\uDFFB-\uDFFF])?|\uDC77(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC78(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC79-\uDC7B]|\uDC7C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC7D-\uDC80]|[\uDC81\uDC82](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC83(?:\uD83C[\uDFFB-\uDFFF])?|\uDC84|\uDC85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC86\uDC87](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDC88-\uDC8E]|\uDC8F(?:\uD83C[\uDFFB-\uDFFF])?|\uDC90|\uDC91(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC92-\uDCA9]|\uDCAA(?:\uD83C[\uDFFB-\uDFFF])?|[\uDCAB-\uDCFC]|\uDCFD\uFE0F?|[\uDCFF-\uDD3D]|[\uDD49\uDD4A]\uFE0F?|[\uDD4B-\uDD4E\uDD50-\uDD67]|[\uDD6F\uDD70\uDD73]\uFE0F?|\uDD74(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|\uDD75(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD76-\uDD79]\uFE0F?|\uDD7A(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD87\uDD8A-\uDD8D]\uFE0F?|\uDD90(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDD95\uDD96](?:\uD83C[\uDFFB-\uDFFF])?|\uDDA4|[\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA]\uFE0F?|[\uDDFB-\uDE2D]|\uDE2E(?:\u200D\uD83D\uDCA8)?|[\uDE2F-\uDE34]|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|[\uDE37-\uDE44]|[\uDE45-\uDE47](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDE48-\uDE4A]|\uDE4B(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDE4C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE4D\uDE4E](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDE4F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE80-\uDEA2]|\uDEA3(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDEA4-\uDEB3]|[\uDEB4-\uDEB6](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDEB7-\uDEBF]|\uDEC0(?:\uD83C[\uDFFB-\uDFFF])?|[\uDEC1-\uDEC5]|\uDECB\uFE0F?|\uDECC(?:\uD83C[\uDFFB-\uDFFF])?|[\uDECD-\uDECF]\uFE0F?|[\uDED0-\uDED2\uDED5-\uDED7]|[\uDEE0-\uDEE5\uDEE9]\uFE0F?|[\uDEEB\uDEEC]|[\uDEF0\uDEF3]\uFE0F?|[\uDEF4-\uDEFC\uDFE0-\uDFEB])|\uD83E(?:\uDD0C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD0D\uDD0E]|\uDD0F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD10-\uDD17]|[\uDD18-\uDD1C](?:\uD83C[\uDFFB-\uDFFF])?|\uDD1D|[\uDD1E\uDD1F](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD20-\uDD25]|\uDD26(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD27-\uDD2F]|[\uDD30-\uDD34](?:\uD83C[\uDFFB-\uDFFF])?|\uDD35(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDD36(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD37-\uDD39](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDD3A|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD3D\uDD3E](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD3F-\uDD45\uDD47-\uDD76]|\uDD77(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD78\uDD7A-\uDDB4]|[\uDDB5\uDDB6](?:\uD83C[\uDFFB-\uDFFF])?|\uDDB7|[\uDDB8\uDDB9](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDBA|\uDDBB(?:\uD83C[\uDFFB-\uDFFF])?|[\uDDBC-\uDDCB]|[\uDDCD-\uDDCF](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDD0|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1|[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|[\uDDD2\uDDD3](?:\uD83C[\uDFFB-\uDFFF])?|\uDDD4(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDD5(?:\uD83C[\uDFFB-\uDFFF])?|[\uDDD6-\uDDDD](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])", RegexOptions.Compiled); - public readonly static Regex chnnelRefRE = new(@"<#([0-9]+)>", RegexOptions.Compiled); - public readonly static Regex iconURLRE = new(@"http[s]{0,1}://[^\.\s]+\.[^\.\s]+\.[^\.\s]+/[^\.\s]+\.[^\s]+", RegexOptions.Compiled); - - public static ulong BotId; - - internal static void LoadParams() { - try { - foreach (var g in Utils.GetClient().Guilds.Values) { - Guilds[g.Id] = g; - } - // Admin Roles - List allAdminRoles = Database.GetAll(); - if (allAdminRoles != null) { - foreach (var r in allAdminRoles) { - ulong gid = r.Guild; - if (!AdminRoles.ContainsKey(gid)) AdminRoles[gid] = new List(); - AdminRoles[gid].Add(r.Role); + /// + /// This command is used to configure the bot, so roles and messages can be set for other servers. + /// author: CPU + /// + public class Configs { + readonly private static Dictionary Guilds = new(); + readonly public static Dictionary TrackChannels = new(); + readonly public static Dictionary> AdminRoles = new(); + readonly public static Dictionary SpamProtections = new(); + readonly public static Dictionary> Tags = new(); + readonly public static Dictionary> SpamLinks = new(); + readonly public static Dictionary> WhiteListLinks = new(); + + readonly public static Dictionary TempRoleSelected = new(); + + public readonly static Regex emjSnowflakeRE = new(@"<:[a-z0-9_]+:([0-9]+)>", RegexOptions.IgnoreCase | RegexOptions.Compiled); + public readonly static Regex roleSnowflakeRR = new("<@[^0-9]+([0-9]*)>", RegexOptions.Compiled); + public readonly static Regex emjUnicodeRE = new(@"[#*0-9]\uFE0F?\u20E3|©\uFE0F?|[®\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA]\uFE0F?|[\u231A\u231B]|[\u2328\u23CF]\uFE0F?|[\u23E9-\u23EC]|[\u23ED-\u23EF]\uFE0F?|\u23F0|[\u23F1\u23F2]\uFE0F?|\u23F3|[\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC]\uFE0F?|[\u25FD\u25FE]|[\u2600-\u2604\u260E\u2611]\uFE0F?|[\u2614\u2615]|\u2618\uFE0F?|\u261D(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642]\uFE0F?|[\u2648-\u2653]|[\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E]\uFE0F?|\u267F|\u2692\uFE0F?|\u2693|[\u2694-\u2697\u2699\u269B\u269C\u26A0]\uFE0F?|\u26A1|\u26A7\uFE0F?|[\u26AA\u26AB]|[\u26B0\u26B1]\uFE0F?|[\u26BD\u26BE\u26C4\u26C5]|\u26C8\uFE0F?|\u26CE|[\u26CF\u26D1\u26D3]\uFE0F?|\u26D4|\u26E9\uFE0F?|\u26EA|[\u26F0\u26F1]\uFE0F?|[\u26F2\u26F3]|\u26F4\uFE0F?|\u26F5|[\u26F7\u26F8]\uFE0F?|\u26F9(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\u26FA\u26FD]|\u2702\uFE0F?|\u2705|[\u2708\u2709]\uFE0F?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|\u270F\uFE0F?|[\u2712\u2714\u2716\u271D\u2721]\uFE0F?|\u2728|[\u2733\u2734\u2744\u2747]\uFE0F?|[\u274C\u274E\u2753-\u2755\u2757]|\u2763\uFE0F?|\u2764(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uFE0F(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?)?|[\u2795-\u2797]|\u27A1\uFE0F?|[\u27B0\u27BF]|[\u2934\u2935\u2B05-\u2B07]\uFE0F?|[\u2B1B\u2B1C\u2B50\u2B55]|[\u3030\u303D\u3297\u3299]\uFE0F?|\uD83C(?:[\uDC04\uDCCF]|[\uDD70\uDD71\uDD7E\uDD7F]\uFE0F?|[\uDD8E\uDD91-\uDD9A]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDE01|\uDE02\uFE0F?|[\uDE1A\uDE2F\uDE32-\uDE36]|\uDE37\uFE0F?|[\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20]|[\uDF21\uDF24-\uDF2C]\uFE0F?|[\uDF2D-\uDF35]|\uDF36\uFE0F?|[\uDF37-\uDF7C]|\uDF7D\uFE0F?|[\uDF7E-\uDF84]|\uDF85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDF86-\uDF93]|[\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F]\uFE0F?|[\uDFA0-\uDFC1]|\uDFC2(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFC5\uDFC6]|\uDFC7(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC8\uDFC9]|\uDFCA(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFCB\uDFCC](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDFCD\uDFCE]\uFE0F?|[\uDFCF-\uDFD3]|[\uDFD4-\uDFDF]\uFE0F?|[\uDFE0-\uDFF0]|\uDFF3(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08)|\uFE0F(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?)?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?|[\uDFF5\uDFF7]\uFE0F?|[\uDFF8-\uDFFF])|\uD83D(?:[\uDC00-\uDC07]|\uDC08(?:\u200D\u2B1B)?|[\uDC09-\uDC14]|\uDC15(?:\u200D\uD83E\uDDBA)?|[\uDC16-\uDC3A]|\uDC3B(?:\u200D\u2744\uFE0F?)?|[\uDC3C-\uDC3E]|\uDC3F\uFE0F?|\uDC40|\uDC41(?:\u200D\uD83D\uDDE8\uFE0F?|\uFE0F(?:\u200D\uD83D\uDDE8\uFE0F?)?)?|[\uDC42\uDC43](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC44\uDC45]|[\uDC46-\uDC50](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC51-\uDC65]|[\uDC66\uDC67](?:\uD83C[\uDFFB-\uDFFF])?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF]|\uDC8B\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC6A|[\uDC6B-\uDC6D](?:\uD83C[\uDFFB-\uDFFF])?|\uDC6E(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDC70\uDC71](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC72(?:\uD83C[\uDFFB-\uDFFF])?|\uDC73(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDC74-\uDC76](?:\uD83C[\uDFFB-\uDFFF])?|\uDC77(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC78(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC79-\uDC7B]|\uDC7C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC7D-\uDC80]|[\uDC81\uDC82](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDC83(?:\uD83C[\uDFFB-\uDFFF])?|\uDC84|\uDC85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC86\uDC87](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDC88-\uDC8E]|\uDC8F(?:\uD83C[\uDFFB-\uDFFF])?|\uDC90|\uDC91(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC92-\uDCA9]|\uDCAA(?:\uD83C[\uDFFB-\uDFFF])?|[\uDCAB-\uDCFC]|\uDCFD\uFE0F?|[\uDCFF-\uDD3D]|[\uDD49\uDD4A]\uFE0F?|[\uDD4B-\uDD4E\uDD50-\uDD67]|[\uDD6F\uDD70\uDD73]\uFE0F?|\uDD74(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|\uDD75(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?|\uFE0F(?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD76-\uDD79]\uFE0F?|\uDD7A(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD87\uDD8A-\uDD8D]\uFE0F?|\uDD90(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDD95\uDD96](?:\uD83C[\uDFFB-\uDFFF])?|\uDDA4|[\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA]\uFE0F?|[\uDDFB-\uDE2D]|\uDE2E(?:\u200D\uD83D\uDCA8)?|[\uDE2F-\uDE34]|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|[\uDE37-\uDE44]|[\uDE45-\uDE47](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDE48-\uDE4A]|\uDE4B(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDE4C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE4D\uDE4E](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDE4F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE80-\uDEA2]|\uDEA3(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDEA4-\uDEB3]|[\uDEB4-\uDEB6](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDEB7-\uDEBF]|\uDEC0(?:\uD83C[\uDFFB-\uDFFF])?|[\uDEC1-\uDEC5]|\uDECB\uFE0F?|\uDECC(?:\uD83C[\uDFFB-\uDFFF])?|[\uDECD-\uDECF]\uFE0F?|[\uDED0-\uDED2\uDED5-\uDED7]|[\uDEE0-\uDEE5\uDEE9]\uFE0F?|[\uDEEB\uDEEC]|[\uDEF0\uDEF3]\uFE0F?|[\uDEF4-\uDEFC\uDFE0-\uDFEB])|\uD83E(?:\uDD0C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD0D\uDD0E]|\uDD0F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD10-\uDD17]|[\uDD18-\uDD1C](?:\uD83C[\uDFFB-\uDFFF])?|\uDD1D|[\uDD1E\uDD1F](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD20-\uDD25]|\uDD26(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD27-\uDD2F]|[\uDD30-\uDD34](?:\uD83C[\uDFFB-\uDFFF])?|\uDD35(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDD36(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD37-\uDD39](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDD3A|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD3D\uDD3E](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDD3F-\uDD45\uDD47-\uDD76]|\uDD77(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD78\uDD7A-\uDDB4]|[\uDDB5\uDDB6](?:\uD83C[\uDFFB-\uDFFF])?|\uDDB7|[\uDDB8\uDDB9](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDBA|\uDDBB(?:\uD83C[\uDFFB-\uDFFF])?|[\uDDBC-\uDDCB]|[\uDDCD-\uDDCF](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDD0|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1|[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|[\uDDD2\uDDD3](?:\uD83C[\uDFFB-\uDFFF])?|\uDDD4(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|\uDDD5(?:\uD83C[\uDFFB-\uDFFF])?|[\uDDD6-\uDDDD](?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F?)?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])", RegexOptions.Compiled); + public readonly static Regex chnnelRefRE = new(@"<#([0-9]+)>", RegexOptions.Compiled); + public readonly static Regex iconURLRE = new(@"http[s]{0,1}://[^\.\s]+\.[^\.\s]+\.[^\.\s]+/[^\.\s]+\.[^\s]+", RegexOptions.Compiled); + + private static ulong botId; + public static ulong BotId { get { return botId; } } + + internal static void LoadParams() { + try { + foreach (var g in Utils.GetClient().Guilds.Values) { + Guilds[g.Id] = g; } - } - // Tracking channels - List allTrackChannels = Database.GetAll(); - if (allTrackChannels != null) { - foreach (var r in allTrackChannels) { - TrackChannels[r.Guild] = r; - if (!Guilds.ContainsKey(r.Guild) && TryGetGuild(r.Guild) == null) continue; // Guild is missing - DiscordChannel ch = Guilds[r.Guild].GetChannel(r.ChannelId); - if (ch == null) { - Utils.Log("Missing track channel id " + r.ChannelId + " from Guild " + Guilds[r.Guild].Name, Guilds[r.Guild].Name); - TrackChannels[r.Guild] = null; - } - else { - r.channel = ch; + // Admin Roles + List allAdminRoles = Database.GetAll(); + if (allAdminRoles != null) { + foreach (var r in allAdminRoles) { + ulong gid = r.Guild; + if (!AdminRoles.ContainsKey(gid)) AdminRoles[gid] = new List(); + AdminRoles[gid].Add(r.Role); } } - } - // Tags - List allTags = Database.GetAll(); - if (allTags != null) { - foreach (var t in allTags) { - ulong gid = t.Guild; - if (!Tags.ContainsKey(gid)) Tags[gid] = new List(); - Tags[gid].Add(t); + // Tracking channels + List allTrackChannels = Database.GetAll(); + if (allTrackChannels != null) { + foreach (var r in allTrackChannels) { + TrackChannels[r.Guild] = r; + if (!Guilds.ContainsKey(r.Guild) && TryGetGuild(r.Guild) == null) continue; // Guild is missing + DiscordChannel ch = Guilds[r.Guild].GetChannel(r.ChannelId); + if (ch == null) { + Utils.Log("Missing track channel id " + r.ChannelId + " from Guild " + Guilds[r.Guild].Name, Guilds[r.Guild].Name); + TrackChannels[r.Guild] = null; + } + else { + r.channel = ch; + } + } } - } - // SpamProtection - List spamProtections = Database.GetAll(); - if (spamProtections != null) { - foreach (var sp in spamProtections) { - SpamProtections[sp.Guild] = sp; + // Tags + List allTags = Database.GetAll(); + if (allTags != null) { + foreach (var t in allTags) { + ulong gid = t.Guild; + if (!Tags.ContainsKey(gid)) Tags[gid] = new List(); + Tags[gid].Add(t); + } } - } - List links = Database.GetAll(); - if (links != null) { - foreach (var sl in links) { - if (sl.whitelist) { - if (!WhiteListLinks.ContainsKey(sl.Guild)) WhiteListLinks[sl.Guild] = new List(); - WhiteListLinks[sl.Guild].Add(sl.link); + + // SpamProtection + List spamProtections = Database.GetAll(); + if (spamProtections != null) { + foreach (var sp in spamProtections) { + SpamProtections[sp.Guild] = sp; } - else { - if (!SpamLinks.ContainsKey(sl.Guild)) SpamLinks[sl.Guild] = new List(); - SpamLinks[sl.Guild].Add(sl.link); + } + List links = Database.GetAll(); + if (links != null) { + foreach (var sl in links) { + if (sl.whitelist) { + if (!WhiteListLinks.ContainsKey(sl.Guild)) WhiteListLinks[sl.Guild] = new List(); + WhiteListLinks[sl.Guild].Add(sl.link); + } + else { + if (!SpamLinks.ContainsKey(sl.Guild)) SpamLinks[sl.Guild] = new List(); + SpamLinks[sl.Guild].Add(sl.link); + } } } - } - // Fill all missing guilds - foreach (var g in Guilds.Keys) { - if (!TrackChannels.ContainsKey(g)) TrackChannels[g] = null; - if (!AdminRoles.ContainsKey(g)) AdminRoles[g] = new List(); - if (!SpamProtections.ContainsKey(g)) SpamProtections[g] = null; - if (!Tags.ContainsKey(g)) Tags[g] = new List(); - if (!TempRoleSelected.ContainsKey(g)) TempRoleSelected[g] = null; - if (!SpamLinks.ContainsKey(g)) SpamLinks[g] = new List(); - if (!WhiteListLinks.ContainsKey(g)) WhiteListLinks[g] = new List(); - } + // Fill all missing guilds + foreach (var g in Guilds.Keys) { + if (!TrackChannels.ContainsKey(g)) TrackChannels[g] = null; + if (!AdminRoles.ContainsKey(g)) AdminRoles[g] = new List(); + if (!SpamProtections.ContainsKey(g)) SpamProtections[g] = null; + if (!Tags.ContainsKey(g)) Tags[g] = new List(); + if (!TempRoleSelected.ContainsKey(g)) TempRoleSelected[g] = null; + if (!SpamLinks.ContainsKey(g)) SpamLinks[g] = new List(); + if (!WhiteListLinks.ContainsKey(g)) WhiteListLinks[g] = new List(); + } - BotId = Utils.GetClient().CurrentUser.Id; + botId = Utils.GetClient().CurrentUser.Id; - Utils.Log("Params fully loaded. " + SpamProtections.Count + " Discord servers found", null); - } catch (Exception ex) { - Utils.Log("Error in ConfigLoadParams:" + ex.Message, null); + Utils.Log("Params fully loaded. " + SpamProtections.Count + " Discord servers found", null); + } catch (Exception ex) { + Utils.Log("Error in ConfigLoadParams:" + ex.Message, null); + } } - } - public static DiscordGuild TryGetGuild(ulong id) { - if (Guilds.ContainsKey(id)) return Guilds[id]; + public static DiscordGuild TryGetGuild(ulong id) { + if (Guilds.ContainsKey(id)) return Guilds[id]; + + Task.Delay(1000); + int t = 0; - Task.Delay(1000); - int t = 0; + // 10 secs max for client + while (Utils.GetClient() == null) { + t++; Task.Delay(t); + if (t > 10) { + Utils.Log("We are not connecting! (no client)", null); + throw new Exception("No discord client"); + } + } - // 10 secs max for client - while (Utils.GetClient() == null) { - t++; Task.Delay(t); - if (t > 10) { - Utils.Log("We are not connecting! (no client)", null); - throw new Exception("No discord client"); + // 10 secs max for guilds + t = 0; + while (Utils.GetClient().Guilds == null) { + t++; Task.Delay(t); + if (t > 10) { + Utils.Log("We are not connecting! (no guilds)", null); + throw new Exception("No guilds avilable"); + } } - } - // 10 secs max for guilds - t = 0; - while (Utils.GetClient().Guilds == null) { - t++; Task.Delay(t); - if (t > 10) { - Utils.Log("We are not connecting! (no guilds)", null); - throw new Exception("No guilds avilable"); + // 30 secs max for guilds coubnt + t = 0; + while (Utils.GetClient().Guilds.Count == 0) { + t++; Task.Delay(t); + if (t > 30) { + Utils.Log("We are not connecting! (guilds count is zero)", null); + throw new Exception("The bot seems to be in no guild"); + } } - } - // 30 secs max for guilds coubnt - t = 0; - while (Utils.GetClient().Guilds.Count == 0) { - t++; Task.Delay(t); - if (t > 30) { - Utils.Log("We are not connecting! (guilds count is zero)", null); - throw new Exception("The bot seems to be in no guild"); + IReadOnlyDictionary cguilds = Utils.GetClient().Guilds; + foreach (var guildId in cguilds.Keys) { + if (!Guilds.ContainsKey(guildId)) Guilds[guildId] = cguilds[guildId]; } - } + if (Guilds.ContainsKey(id)) return Guilds[id]; - IReadOnlyDictionary cguilds = Utils.GetClient().Guilds; - foreach (var guildId in cguilds.Keys) { - if (!Guilds.ContainsKey(guildId)) Guilds[guildId] = cguilds[guildId]; + return null; } - if (Guilds.ContainsKey(id)) return Guilds[id]; - return null; - } + internal static Task NewGuildAdded(DSharpPlus.DiscordClient _, GuildCreateEventArgs e) { + DiscordGuild g = e.Guild; + ulong gid = g.Id; + // Do we have the guild? + if (TryGetGuild(gid) == null) { // No, that is a problem. + Utils.Log("Impossible to connect to a new Guild: " + g.Name, null); + return Task.FromResult(0); + } + // Fill all values + TrackChannels[gid] = null; + AdminRoles[gid] = new List(); + SpamProtections[gid] = null; + Tags[gid] = new List(); + TempRoleSelected[gid] = null; + Utils.Log("Guild " + g.Name + " joined", g.Name); + Utils.Log("Guild " + g.Name + " joined", null); - internal static Task NewGuildAdded(DSharpPlus.DiscordClient _, GuildCreateEventArgs e) { - DiscordGuild g = e.Guild; - ulong gid = g.Id; - // Do we have the guild? - if (TryGetGuild(gid) == null) { // No, that is a problem. - Utils.Log("Impossible to connect to a new Guild: " + g.Name, null); return Task.FromResult(0); } - // Fill all values - TrackChannels[gid] = null; - AdminRoles[gid] = new List(); - SpamProtections[gid] = null; - Tags[gid] = new List(); - TempRoleSelected[gid] = null; - Utils.Log("Guild " + g.Name + " joined", g.Name); - Utils.Log("Guild " + g.Name + " joined", null); - - return Task.FromResult(0); - } - internal static bool IsAdminRole(ulong guild, DiscordRole role) { - if (AdminRoles[guild].Contains(role.Id)) return true; - return (role.Permissions.HasFlag(DSharpPlus.Permissions.Administrator)); // Fall back - } - internal static bool HasAdminRole(ulong guild, IEnumerable roles, bool withManageMessages) { - if (AdminRoles[guild] == null || AdminRoles[guild].Count == 0) return true; - foreach (var r in roles) - if (AdminRoles[guild].Contains(r.Id)) return true; - foreach (var r in roles) - if (r.Permissions.HasFlag(DSharpPlus.Permissions.Administrator) || (withManageMessages && r.Permissions.HasFlag(DSharpPlus.Permissions.ManageMessages))) return true; - return false; - } + internal static bool IsAdminRole(ulong guild, DiscordRole role) { + if (AdminRoles[guild].Contains(role.Id)) return true; + return (role.Permissions.HasFlag(DSharpPlus.Permissions.Administrator)); // Fall back + } + internal static bool HasAdminRole(ulong guild, IEnumerable roles, bool withManageMessages) { + if (AdminRoles[guild] == null || AdminRoles[guild].Count == 0) return true; + foreach (var r in roles) + if (AdminRoles[guild].Contains(r.Id)) return true; + foreach (var r in roles) + if (r.Permissions.HasFlag(DSharpPlus.Permissions.Administrator) || (withManageMessages && r.Permissions.HasFlag(DSharpPlus.Permissions.ManageMessages))) return true; + return false; + } - internal static string GetAdminsMentions(ulong gid) { - if (!AdminRoles.ContainsKey(gid) || AdminRoles[gid].Count == 0) return "Admins"; - string res = ""; - foreach (var rid in AdminRoles[gid]) { - DiscordRole r = Guilds[gid].GetRole(rid); - if (r != null) res += r.Mention + " "; + internal static string GetAdminsMentions(ulong gid) { + if (!AdminRoles.ContainsKey(gid) || AdminRoles[gid].Count == 0) return "Admins"; + string res = ""; + foreach (var rid in AdminRoles[gid]) { + DiscordRole r = Guilds[gid].GetRole(rid); + if (r != null) res += r.Mention + " "; + } + if (res.Length > 0) return res[0..^1]; + return "Admins"; } - if (res.Length > 0) return res[0..^1]; - return "Admins"; - } -} + } +} \ No newline at end of file diff --git a/UPBot Code/DataClasses/TagBase.cs b/UPBot Code/DataClasses/TagBase.cs index 4881e06..d3734e1 100644 --- a/UPBot Code/DataClasses/TagBase.cs +++ b/UPBot Code/DataClasses/TagBase.cs @@ -1,34 +1,36 @@ using System; -public class TagBase : Entity { - [Key] public ulong Guild; - [Key] public string Topic; - public string Alias1; - public string Alias2; - public string Alias3; - [Comment] public string Information; - public string Author; - public string AuthorIcon; - public long ColorOfTheme; - public DateTime timeOfCreation; - public string thumbnailLink; - public string imageLink; +namespace UPBot { + public class TagBase : Entity { + [Key] public ulong Guild; + [Key] public string Topic; + public string Alias1; + public string Alias2; + public string Alias3; + [Comment] public string Information; + public string Author; + public long ColorOfTheme; + public DateTime timeOfCreation; + public string thumbnailLink; + public string AuthorIcon; + public string imageLink; - public TagBase() { } + public TagBase() { } - public TagBase(ulong guild, string topic, string info, string author, string authorIcon, int colorOfTheme, DateTime time, string thumbnailLink, string imageLink) - { - Guild = guild; - Topic = topic; - Alias1 = null; - Alias2 = null; - Alias3 = null; - Information = info; - Author = author; - AuthorIcon = authorIcon; - ColorOfTheme = colorOfTheme; - timeOfCreation = time; - this.thumbnailLink = thumbnailLink; - this.imageLink = imageLink; + public TagBase(ulong guild, string topic, string info, string author, string authorIcon, int colorOfTheme, DateTime time, string thumbnailLink, string imageLink) { + Guild = guild; + Topic = topic; + Alias1 = null; + Alias2 = null; + Alias3 = null; + Information = info; + Author = author; + AuthorIcon = authorIcon; + ColorOfTheme = colorOfTheme; + timeOfCreation = time; + this.thumbnailLink = thumbnailLink; + this.imageLink = imageLink; } -} + } + +} \ No newline at end of file