From c69fbf7b103dd67dc49e78af5a2451f37e221306 Mon Sep 17 00:00:00 2001 From: CPULL Date: Thu, 19 Aug 2021 12:28:48 +0200 Subject: [PATCH] Completed bot finalization --- ToDo.txt | 30 + UPBot Code/Actions/AppreciationTracking.cs | 547 ++++++++++--------- UPBot Code/Actions/MembersTracking.cs | 68 ++- UPBot Code/Commands/BannedWords.cs | 180 +++--- UPBot Code/Commands/CustomCommand.cs | 2 +- UPBot Code/Commands/CustomCommandsService.cs | 45 +- UPBot Code/Commands/DebugCommand.cs | 26 - UPBot Code/Commands/Delete.cs | 155 +++--- UPBot Code/Commands/Game.cs | 8 +- UPBot Code/Commands/HelpLanguages.cs | 25 +- UPBot Code/Commands/Ping.cs | 74 +-- UPBot Code/Commands/Refactor.cs | 162 +++--- UPBot Code/Commands/Stats.cs | 79 ++- UPBot Code/Commands/Version.cs | 27 + UPBot Code/Commands/WhoIs.cs | 138 ++--- UPBot Code/Program.cs | 6 +- UPBot Code/{UtilityFunctions.cs => Utils.cs} | 76 ++- 17 files changed, 920 insertions(+), 728 deletions(-) create mode 100644 ToDo.txt delete mode 100644 UPBot Code/Commands/DebugCommand.cs create mode 100644 UPBot Code/Commands/Version.cs rename UPBot Code/{UtilityFunctions.cs => Utils.cs} (81%) diff --git a/ToDo.txt b/ToDo.txt new file mode 100644 index 0000000..176e056 --- /dev/null +++ b/ToDo.txt @@ -0,0 +1,30 @@ +ο»ΏHave command to alter the command character [NOT POSSIBLE!] +Check all command names +Add wikis for each command on GitHub +Uniform all error messages with Embeds (use Duck code) +Have all messages and commands to disappear after a while (configurable) if not needed to stay +Have a cmd to configure how long messages should stay +Add TryCatch to all code and commands + + + Errors DelAnsw EmbedRes TryCatch Log@Begin +MemberTracking | | | | X | | +Appreciation | | | | X | X | +EmojiForRole | | | | X | X | +BannedWords | | X | | X | X | +newcc | | | | | X | +ccdel | | | | | X | +ccedit | | | | | X | +cceditname | | | | | X | +cclist | | | | | X | +delete | X | X | | X | X | +game | | | | | X | +bool | | | | | X | +rps | | | | | X | +helplanguage | | | X | X | X | +ping | | X | | X | X | +checklanguage | | | | X | X | +reformat | | | | X | X | +stats | | | X | X | X | +whois | | | X | X | X | + diff --git a/UPBot Code/Actions/AppreciationTracking.cs b/UPBot Code/Actions/AppreciationTracking.cs index 37b68e5..8401a28 100644 --- a/UPBot Code/Actions/AppreciationTracking.cs +++ b/UPBot Code/Actions/AppreciationTracking.cs @@ -12,71 +12,81 @@ public class AppreciationTracking : BaseCommandModule { static ReputationTracking tracking = null; static EmojisForRole emojisForRole = null; static bool savingRequested = false; - + public static void Init() { - tracking = new ReputationTracking(UtilityFunctions.ConstructPath("Tracking", "Tracking", ".Tracking")); - emojisForRole = new EmojisForRole(UtilityFunctions.ConstructPath("Tracking", "EmojisForRole", ".dat")); + tracking = new ReputationTracking(Utils.ConstructPath("Tracking", "Tracking", ".Tracking")); + emojisForRole = new EmojisForRole(Utils.ConstructPath("Tracking", "EmojisForRole", ".dat")); } [Command("Appreciation")] [Description("It shows the statistics for users")] public async Task ShowAppreciationCommand(CommandContext ctx) { - UtilityFunctions.LogUserCommand(ctx); - if (tracking == null) { - tracking = new ReputationTracking(UtilityFunctions.ConstructPath("Tracking", "Tracking", ".Tracking")); - if (tracking == null) return; - } - DiscordEmbedBuilder e = UtilityFunctions.BuildEmbed("Appreciation", "These are the most appreciated people of this server (tracking started at " + tracking.GetStartDate() + ")", DiscordColor.Azure); - - List vals = new List(tracking.GetReputation()); - Dictionary users = new Dictionary(); - e.AddField("Reputation ----------------", "For receving these emojis in the posts: <:OK:830907665869570088>πŸ‘β€οΈπŸ₯°πŸ˜πŸ€©πŸ˜˜πŸ’―<:whatthisguysaid:840702597216337990>", false); - vals.Sort((a, b) => { return b.reputation.CompareTo(a.reputation); }); - for (int i = 0; i < 6; i++) { - if (i >= vals.Count) break; - Reputation r = vals[i]; - if (r.reputation == 0) break; - if (!users.ContainsKey(r.user)) { - users[r.user] = ctx.Guild.GetMemberAsync(r.user).Result.DisplayName; + Utils.LogUserCommand(ctx); + try { + if (tracking == null) { + tracking = new ReputationTracking(Utils.ConstructPath("Tracking", "Tracking", ".Tracking")); + if (tracking == null) return; + } + DiscordEmbedBuilder e = Utils.BuildEmbed("Appreciation", "These are the most appreciated people of this server (tracking started at " + tracking.GetStartDate() + ")", DiscordColor.Azure); + + List vals = new List(tracking.GetReputation()); + Dictionary users = new Dictionary(); + e.AddField("Reputation ----------------", "For receving these emojis in the posts: <:OK:830907665869570088>πŸ‘β€οΈπŸ₯°πŸ˜πŸ€©πŸ˜˜πŸ’―<:whatthisguysaid:840702597216337990>", false); + vals.Sort((a, b) => { return b.reputation.CompareTo(a.reputation); }); + for (int i = 0; i < 6; i++) { + if (i >= vals.Count) break; + Reputation r = vals[i]; + if (r.reputation == 0) break; + if (!users.ContainsKey(r.user)) { + users[r.user] = ctx.Guild.GetMemberAsync(r.user).Result.DisplayName; + } + e.AddField(users[r.user], "Reputation: _" + r.reputation + "_", true); } - e.AddField(users[r.user], "Reputation: _" + r.reputation + "_", true); - } - e.AddField("Fun -----------------------", "For receving these emojis in the posts: πŸ˜€πŸ˜ƒπŸ˜„πŸ˜πŸ˜†πŸ˜…πŸ€£πŸ˜‚πŸ™‚πŸ™ƒπŸ˜‰πŸ˜ŠπŸ˜‡<:StrongSmile:830907626928996454>", false); - vals.Sort((a, b) => { return b.fun.CompareTo(a.fun); }); - for (int i = 0; i < 6; i++) { - if (i >= vals.Count) break; - Reputation r = vals[i]; - if (r.fun == 0) break; - if (!users.ContainsKey(r.user)) { - users[r.user] = ctx.Guild.GetMemberAsync(r.user).Result.DisplayName; + e.AddField("Fun -----------------------", "For receving these emojis in the posts: πŸ˜€πŸ˜ƒπŸ˜„πŸ˜πŸ˜†πŸ˜…πŸ€£πŸ˜‚πŸ™‚πŸ™ƒπŸ˜‰πŸ˜ŠπŸ˜‡<:StrongSmile:830907626928996454>", false); + vals.Sort((a, b) => { return b.fun.CompareTo(a.fun); }); + for (int i = 0; i < 6; i++) { + if (i >= vals.Count) break; + Reputation r = vals[i]; + if (r.fun == 0) break; + if (!users.ContainsKey(r.user)) { + users[r.user] = ctx.Guild.GetMemberAsync(r.user).Result.DisplayName; + } + e.AddField(users[r.user], "Fun: _" + r.fun + "_", (i < vals.Count - 1 && i < 5)); } - e.AddField(users[r.user], "Fun: _" + r.fun + "_", (i < vals.Count - 1 && i < 5)); - } - await ctx.Message.RespondAsync(e.Build()); + await ctx.Message.RespondAsync(e.Build()); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("Appreciation", ex)); + } } [Command("EmojiForRole")] + [Aliases("RoleForEmoji")] [RequireRoles(RoleCheckMode.Any, "Mod", "Owner", "Helper")] // Restrict access to users with the "Mod" or "Owner" role only [Description("Reply to a message what should add and remove a role when an emoji (any or specific) is added")] public async Task EmojiForRoleCommand(CommandContext ctx, [Description("The role to add")] DiscordRole role, [Description("The emoji to watch")] DiscordEmoji emoji) { - if (ctx.Message.ReferencedMessage == null) { - await UtilityFunctions.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched!", UtilityFunctions.Red, ctx, true); - } - else { - string msg = ctx.Message.ReferencedMessage.Content; - if (msg.Length > 20) msg = msg.Substring(0, 20) + "..."; - if (emojisForRole.AddRemove(ctx.Message.ReferencedMessage, role, emoji)) { - msg = "The referenced message (_" + msg + "_) will grant/remove the role *" + role.Name + "* when adding/removing the emoji: " + emoji.GetDiscordName(); + Utils.LogUserCommand(ctx); + try { + if (ctx.Message.ReferencedMessage == null) { + await Utils.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched!", Utils.Red, ctx, true); } else { - msg = "The message referenced (_" + msg + "_) will not grant anymore the role *" + role.Name + "* when adding the emoji: " + emoji.GetDiscordName(); + string msg = ctx.Message.ReferencedMessage.Content; + if (msg.Length > 20) msg = msg.Substring(0, 20) + "..."; + if (emojisForRole.AddRemove(ctx.Message.ReferencedMessage, role, emoji)) { + msg = "The referenced message (_" + msg + "_) will grant/remove the role *" + role.Name + "* when adding/removing the emoji: " + emoji.GetDiscordName(); + } + else { + msg = "The message referenced (_" + msg + "_) will not grant anymore the role *" + role.Name + "* when adding the emoji: " + emoji.GetDiscordName(); + } + Utils.Log(msg); + await ctx.RespondAsync(msg); } - UtilityFunctions.Log(msg); - await ctx.RespondAsync(msg); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("EmojiForRole", ex)); } } @@ -84,37 +94,44 @@ public async Task EmojiForRoleCommand(CommandContext ctx, [Description("The role [Command("EmojiForRole")] [RequireRoles(RoleCheckMode.Any, "Mod", "Owner", "Helper")] // Restrict access to users with the "Mod" or "Owner" role only public async Task EmojiForRoleCommand(CommandContext ctx) { - await UtilityFunctions.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\nyou have to specify the Role to add/remove, and the emoji to watch.", UtilityFunctions.Red, ctx, true); + Utils.LogUserCommand(ctx); + await Utils.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\nyou have to specify the Role to add/remove, and the emoji to watch.", Utils.Red, ctx, true); } [Command("EmojiForRole")] [RequireRoles(RoleCheckMode.Any, "Mod", "Owner", "Helper")] // Restrict access to users with the "Mod" or "Owner" role only public async Task EmojiForRoleCommand(CommandContext ctx, [Description("The role to add")] DiscordRole role) { - if (ctx.Message.ReferencedMessage == null) { - await UtilityFunctions.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\n and you have to specify the emoji to watch.", UtilityFunctions.Red, ctx, true); - } - else { - string msg = ctx.Message.ReferencedMessage.Content; - if (msg.Length > 20) msg = msg.Substring(0, 20) + "..."; - if (emojisForRole.AddRemove(ctx.Message.ReferencedMessage, role, null)) { - msg = "The referenced message (_" + msg + "_) will grant/remove the role *" + role.Name + "* when adding/removing any emoji"; + Utils.LogUserCommand(ctx); + try { + if (ctx.Message.ReferencedMessage == null) { + await Utils.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\n and you have to specify the emoji to watch.", Utils.Red, ctx, true); } else { - msg = "The message referenced (_" + msg + "_) will not grant anymore the role *" + role.Name + "* when adding an emoji"; + string msg = ctx.Message.ReferencedMessage.Content; + if (msg.Length > 20) msg = msg.Substring(0, 20) + "..."; + if (emojisForRole.AddRemove(ctx.Message.ReferencedMessage, role, null)) { + msg = "The referenced message (_" + msg + "_) will grant/remove the role *" + role.Name + "* when adding/removing any emoji"; + } + else { + msg = "The message referenced (_" + msg + "_) will not grant anymore the role *" + role.Name + "* when adding an emoji"; + } + Utils.Log(msg); + await ctx.RespondAsync(msg); } - UtilityFunctions.Log(msg); - await ctx.RespondAsync(msg); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("EmojiForRole", ex)); } } [Command("EmojiForRole")] [RequireRoles(RoleCheckMode.Any, "Mod", "Owner", "Helper")] // Restrict access to users with the "Mod" or "Owner" role only public async Task EmojiForRoleCommand(CommandContext ctx, [Description("The emoji to watch")] DiscordEmoji emoji) { + Utils.LogUserCommand(ctx); if (ctx.Message.ReferencedMessage == null) { - await UtilityFunctions.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\nand y ou have to specify the Role to add/remove.", UtilityFunctions.Red, ctx, true); + await Utils.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to reply to the message that should be watched,\nand y ou have to specify the Role to add/remove.", Utils.Red, ctx, true); } else { - await UtilityFunctions.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to specify the Role to add/remove.", UtilityFunctions.Red, ctx, true); + await Utils.BuildEmbedAndExecute("EmojiForRole - Bad parameters", "You have to specify the Role to add/remove.", Utils.Red, ctx, true); } } @@ -122,61 +139,72 @@ public async Task EmojiForRoleCommand(CommandContext ctx, [Description("The emoj internal static Task ReacionAdded(DiscordClient sender, MessageReactionAddEventArgs a) { - ulong emojiId = a.Emoji.Id; - string emojiName = a.Emoji.Name; - emojisForRole.HandleAddingEmojiForRole(a.Message.ChannelId, emojiId, emojiName, a.User, a.Message.Id); - - DiscordUser author = a.Message.Author; - if (author == null) { - ulong msgId = a.Message.Id; - ulong chId = a.Message.ChannelId; - DiscordChannel c = a.Guild.GetChannel(chId); - DiscordMessage m = c.GetMessageAsync(msgId).Result; - author = m.Author; + try { + ulong emojiId = a.Emoji.Id; + string emojiName = a.Emoji.Name; + emojisForRole.HandleAddingEmojiForRole(a.Message.ChannelId, emojiId, emojiName, a.User, a.Message.Id); + + DiscordUser author = a.Message.Author; + if (author == null) { + ulong msgId = a.Message.Id; + ulong chId = a.Message.ChannelId; + DiscordChannel c = a.Guild.GetChannel(chId); + DiscordMessage m = c.GetMessageAsync(msgId).Result; + author = m.Author; + } + ulong authorId = author.Id; + if (authorId == a.User.Id) return Task.Delay(10); // If member is equal to author ignore (no self emojis) + return HandleReactions(emojiId, emojiName, authorId, true); + } catch (Exception ex) { + Utils.Log("Error in ReacionAdded: " + ex.Message); + return Task.FromResult(0); } - ulong authorId = author.Id; - if (authorId == a.User.Id) return Task.Delay(10); // If member is equal to author ignore (no self emojis) - return HandleReactions(emojiId, emojiName, authorId, true); } + internal static Task ReactionRemoved(DiscordClient sender, MessageReactionRemoveEventArgs a) { - ulong emojiId = a.Emoji.Id; - string emojiName = a.Emoji.Name; - emojisForRole.HandleRemovingEmojiForRole(a.Message.ChannelId, emojiId, emojiName, a.User, a.Message.Id); - - DiscordUser author = a.Message.Author; - if (author == null) { - ulong msgId = a.Message.Id; - ulong chId = a.Message.ChannelId; - DiscordChannel c = a.Guild.GetChannel(chId); - DiscordMessage m = c.GetMessageAsync(msgId).Result; - author = m.Author; + try { + ulong emojiId = a.Emoji.Id; + string emojiName = a.Emoji.Name; + emojisForRole.HandleRemovingEmojiForRole(a.Message.ChannelId, emojiId, emojiName, a.User, a.Message.Id); + + DiscordUser author = a.Message.Author; + if (author == null) { + ulong msgId = a.Message.Id; + ulong chId = a.Message.ChannelId; + DiscordChannel c = a.Guild.GetChannel(chId); + DiscordMessage m = c.GetMessageAsync(msgId).Result; + author = m.Author; + } + ulong authorId = author.Id; + if (authorId == a.User.Id) return Task.Delay(10); // If member is equal to author ignore (no self emojis) + return HandleReactions(emojiId, emojiName, authorId, false); + } catch (Exception ex) { + Utils.Log("Error in ReacionAdded: " + ex.Message); + return Task.FromResult(0); } - ulong authorId = author.Id; - if (authorId == a.User.Id) return Task.Delay(10); // If member is equal to author ignore (no self emojis) - return HandleReactions(emojiId, emojiName, authorId, false); } static Task HandleReactions(ulong emojiId, string emojiName, ulong authorId, bool added) { bool save = false; // check if emoji is :smile: :rolf: :strongsmil: (find valid emojis -> increase fun level of user - if (emojiName == "πŸ˜€" || - emojiName == "πŸ˜ƒ" || - emojiName == "πŸ˜„" || - emojiName == "😁" || - emojiName == "πŸ˜†" || - emojiName == "πŸ˜…" || - emojiName == "🀣" || - emojiName == "πŸ˜‚" || - emojiName == "πŸ™‚" || - emojiName == "πŸ™ƒ" || - emojiName == "πŸ˜‰" || - emojiName == "😊" || - emojiName == "πŸ˜‡" || + if (emojiName == "πŸ˜€" || + emojiName == "πŸ˜ƒ" || + emojiName == "πŸ˜„" || + emojiName == "😁" || + emojiName == "πŸ˜†" || + emojiName == "πŸ˜…" || + emojiName == "🀣" || + emojiName == "πŸ˜‚" || + emojiName == "πŸ™‚" || + emojiName == "πŸ™ƒ" || + emojiName == "πŸ˜‰" || + emojiName == "😊" || + emojiName == "πŸ˜‡" || emojiId == 830907626928996454ul || // :StrongSmile: false) { // just to keep the other lines aligned if (tracking == null) { - tracking = new ReputationTracking(UtilityFunctions.ConstructPath("Tracking", "Tracking", ".Tracking")); + tracking = new ReputationTracking(Utils.ConstructPath("Tracking", "Tracking", ".Tracking")); if (tracking == null) return Task.Delay(10); } save = tracking.AlterFun(authorId, added); @@ -194,7 +222,7 @@ static Task HandleReactions(ulong emojiId, string emojiName, ulong authorId, boo emojiId == 552147917876625419ul || // :thoose: false) { // just to keep the other lines aligned if (tracking == null) { - tracking = new ReputationTracking(UtilityFunctions.ConstructPath("Tracking", "Tracking", ".Tracking")); + tracking = new ReputationTracking(Utils.ConstructPath("Tracking", "Tracking", ".Tracking")); if (tracking == null) return Task.Delay(10); } save = tracking.AlterRep(authorId, added); @@ -216,7 +244,7 @@ static async Task SaveDelayedAsync() { try { tracking.Save(); } catch (Exception e) { - UtilityFunctions.Log("ERROR: problems in saving the Reputation file: " + e.Message); + Utils.Log("ERROR: problems in saving the Reputation file: " + e.Message); } savingRequested = false; } @@ -230,71 +258,79 @@ public class Reputation { // 16 bytes } public class ReputationTracking { - DateTime trackingStarted; - Dictionary dic; - string path = null; + readonly DateTime trackingStarted; + readonly Dictionary dic; + readonly string path = null; public ReputationTracking(string path) { - this.path = path; - dic = new Dictionary(); - if (!File.Exists(path)) { - trackingStarted = DateTime.Now; - return; - } - byte[] data = new byte[20]; - using (FileStream f = new FileStream(path, FileMode.Open)) { - // 32 bits for the date (ymd) - if (f.Read(data, 0, 4) < 4) { - UtilityFunctions.Log("ERROR: wrong Reputation file: " + path); - try { - if (File.Exists(path)) File.Delete(path); - } catch (Exception e) { - UtilityFunctions.Log("ERROR: cannot delete old Reputation file: " + path + "\nException: " + e.Message); - } + try { + this.path = path; + dic = new Dictionary(); + if (!File.Exists(path)) { + trackingStarted = DateTime.Now; return; } - trackingStarted = GetDateFromBytes(data, 0); - while (f.Read(data, 0, 16) == 16) { - ulong usrid = BitConverter.ToUInt64(data); - ushort rep = BitConverter.ToUInt16(data, 8); - ushort fun = BitConverter.ToUInt16(data, 10); - DateTime start = GetDateFromBytes(data, 12); - dic[usrid] = new Reputation { user = usrid, reputation = rep, fun = fun, startTracking = start }; + byte[] data = new byte[20]; + using (FileStream f = new FileStream(path, FileMode.Open)) { + // 32 bits for the date (ymd) + if (f.Read(data, 0, 4) < 4) { + Utils.Log("ERROR: wrong Reputation file: " + path); + try { + if (File.Exists(path)) File.Delete(path); + } catch (Exception e) { + Utils.Log("ERROR: cannot delete old Reputation file: " + path + "\nException: " + e.Message); + } + return; + } + trackingStarted = GetDateFromBytes(data, 0); + while (f.Read(data, 0, 16) == 16) { + ulong usrid = BitConverter.ToUInt64(data); + ushort rep = BitConverter.ToUInt16(data, 8); + ushort fun = BitConverter.ToUInt16(data, 10); + DateTime start = GetDateFromBytes(data, 12); + dic[usrid] = new Reputation { user = usrid, reputation = rep, fun = fun, startTracking = start }; + } } + Utils.Log("ReputationTracking: Loaded " + dic.Count + " users"); + } catch (Exception e) { + Utils.Log("ERROR: problems in loading the Reputation file: " + e.Message); } - UtilityFunctions.Log("ReputationTracking: Loaded " + dic.Count + " users"); } public void Save() { - lock (dic) { - try { - if (File.Exists(path)) File.Delete(path); - } catch (Exception e) { - UtilityFunctions.Log("ERROR: cannot delete old Reputation file: " + path + "\nException: " + e.Message); - return; - } - using (FileStream f = new FileStream(path, FileMode.CreateNew)) { - byte[] data = new byte[16]; - SetDateToBytes(trackingStarted, data, 0); - f.Write(data, 0, 4); - foreach (Reputation r in dic.Values) { - byte[] d = BitConverter.GetBytes(r.user); - int pos = 0; - for (int i = 0; i < d.Length; i++) - data[pos++] = d[i]; - d = BitConverter.GetBytes(r.reputation); - for (int i = 0; i < d.Length; i++) - data[pos++] = d[i]; - d = BitConverter.GetBytes(r.fun); - for (int i = 0; i < d.Length; i++) - data[pos++] = d[i]; - SetDateToBytes(r.startTracking, data, pos); - f.Write(data, 0, 16); + try { + lock (dic) { + try { + if (File.Exists(path)) File.Delete(path); + } catch (Exception e) { + Utils.Log("ERROR: cannot delete old Reputation file: " + path + "\nException: " + e.Message); + return; + } + using (FileStream f = new FileStream(path, FileMode.CreateNew)) { + byte[] data = new byte[16]; + SetDateToBytes(trackingStarted, data, 0); + f.Write(data, 0, 4); + foreach (Reputation r in dic.Values) { + byte[] d = BitConverter.GetBytes(r.user); + int pos = 0; + for (int i = 0; i < d.Length; i++) + data[pos++] = d[i]; + d = BitConverter.GetBytes(r.reputation); + for (int i = 0; i < d.Length; i++) + data[pos++] = d[i]; + d = BitConverter.GetBytes(r.fun); + for (int i = 0; i < d.Length; i++) + data[pos++] = d[i]; + SetDateToBytes(r.startTracking, data, pos); + f.Write(data, 0, 16); + } + f.Flush(); } - f.Flush(); } + Utils.Log("ReputationTracking: Saved " + dic.Count + " users"); + } catch (Exception e) { + Utils.Log("ERROR: problems in saving the Reputation file: " + e.Message); } - UtilityFunctions.Log("ReputationTracking: Saved " + dic.Count + " users"); } private void SetDateToBytes(DateTime d, byte[] data, int offset) { @@ -305,7 +341,11 @@ private void SetDateToBytes(DateTime d, byte[] data, int offset) { } private DateTime GetDateFromBytes(byte[] data, int offset) { - return new DateTime((data[offset + 0] << 8) + data[offset + 1], data[offset + 2], data[offset + 3]); + try { + return new DateTime((data[offset + 0] << 8) + data[offset + 1], data[offset + 2], data[offset + 3]); + } catch (Exception) { + return DateTime.Now; + } } public bool AlterRep(ulong id, bool add) { @@ -355,87 +395,96 @@ public class EmojisForRole { string path = null; public EmojisForRole(string path) { - values = new List(); - this.path = path; - if (!File.Exists(path)) return; - - DiscordGuild g = UtilityFunctions.GetGuild(); - byte[] data = new byte[36]; - using (FileStream f = new FileStream(path, FileMode.Open)) { - while (f.Read(data, 0, 36) == 36) { - ReactionValue v = new ReactionValue { - channel = BitConverter.ToUInt64(data, 0), - message = BitConverter.ToUInt64(data, 8), - role = BitConverter.ToUInt64(data, 16), - emojiId = BitConverter.ToUInt64(data, 24), - emojiName = Char.ConvertFromUtf32(BitConverter.ToInt32(data, 32)), - dRole = null - }; - - DiscordMessage m; - try { - // Does the message exists? - DiscordChannel c = g.GetChannel(v.channel); - if (c == null || c.Id == 0) continue; // Bad - m = c.GetMessageAsync(v.message).Result; - if (m == null || m.Id == 0) continue; // Bad; - // Does the role exists? - DiscordRole r = g.GetRole(v.role); - if (r == null || r.Id == 0) continue; // Bad - } catch (Exception ex) { - UtilityFunctions.Log("Error while checking a ReactionValue: " + ex.Message); - continue; - } - // Check that the message has the required emojis, if not add it - DiscordEmoji e = null; - if (v.emojiId != 0) { - e = g.GetEmojiAsync(v.emojiId).Result; - } else if (v.emojiName != "!") { - e = DiscordEmoji.FromUnicode(v.emojiName); - } - if (e == null) continue; // Bad - if (m.GetReactionsAsync(e, 1).Result.Count == 0) { // Need to add - m.CreateReactionAsync(e).Wait(); - } + try { + values = new List(); + this.path = path; + if (!File.Exists(path)) return; + + DiscordGuild g = Utils.GetGuild(); + byte[] data = new byte[36]; + using (FileStream f = new FileStream(path, FileMode.Open)) { + while (f.Read(data, 0, 36) == 36) { + ReactionValue v = new ReactionValue { + channel = BitConverter.ToUInt64(data, 0), + message = BitConverter.ToUInt64(data, 8), + role = BitConverter.ToUInt64(data, 16), + emojiId = BitConverter.ToUInt64(data, 24), + emojiName = Char.ConvertFromUtf32(BitConverter.ToInt32(data, 32)), + dRole = null + }; + + DiscordMessage m; + try { + // Does the message exists? + DiscordChannel c = g.GetChannel(v.channel); + if (c == null || c.Id == 0) continue; // Bad + m = c.GetMessageAsync(v.message).Result; + if (m == null || m.Id == 0) continue; // Bad; + // Does the role exists? + DiscordRole r = g.GetRole(v.role); + if (r == null || r.Id == 0) continue; // Bad + } catch (Exception ex) { + Utils.Log("Error while checking a ReactionValue: " + ex.Message); + continue; + } + // Check that the message has the required emojis, if not add it + DiscordEmoji e = null; + if (v.emojiId != 0) { + e = g.GetEmojiAsync(v.emojiId).Result; + } + else if (v.emojiName != "!") { + e = DiscordEmoji.FromUnicode(v.emojiName); + } + if (e == null) continue; // Bad + if (m.GetReactionsAsync(e, 1).Result.Count == 0) { // Need to add + m.CreateReactionAsync(e).Wait(); + } - values.Add(v); + values.Add(v); + } } + Utils.Log("Loaded " + values.Count + " tracked messages for emojis."); + } catch (Exception e) { + Utils.Log("ERROR: problems in loading the EmojiForRole file: " + e.Message); } - UtilityFunctions.Log("Loaded " + values.Count + " tracked messages for emojis."); } public void Save() { - lock (values) { - try { - if (File.Exists(path)) File.Delete(path); - } catch (Exception e) { - UtilityFunctions.Log("ERROR: cannot delete old EmojisForRole file: " + path + "\nException: " + e.Message); - return; - } - using (FileStream f = new FileStream(path, FileMode.CreateNew)) { - byte[] data = new byte[36]; - foreach (ReactionValue v in values) { - int pos = 0; - byte[] d = BitConverter.GetBytes(v.channel); - for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; - d = BitConverter.GetBytes(v.message); - for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; - d = BitConverter.GetBytes(v.role); - for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; - d = BitConverter.GetBytes(v.emojiId); - for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; - if (v.emojiId != 0 || v.emojiName == null || v.emojiName.Length == 0) - for (int i = 0; i < 4; i++) data[pos++] = 0; - else { - d = BitConverter.GetBytes(Char.ConvertToUtf32(v.emojiName, 0)); - for (int i = 0; i < 4; i++) data[pos++] = d[i]; + try { + lock (values) { + try { + if (File.Exists(path)) File.Delete(path); + } catch (Exception e) { + Utils.Log("ERROR: cannot delete old EmojisForRole file: " + path + "\nException: " + e.Message); + return; + } + using (FileStream f = new FileStream(path, FileMode.CreateNew)) { + byte[] data = new byte[36]; + foreach (ReactionValue v in values) { + int pos = 0; + byte[] d = BitConverter.GetBytes(v.channel); + for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; + d = BitConverter.GetBytes(v.message); + for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; + d = BitConverter.GetBytes(v.role); + for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; + d = BitConverter.GetBytes(v.emojiId); + for (int i = 0; i < d.Length; i++) data[pos++] = d[i]; + if (v.emojiId != 0 || v.emojiName == null || v.emojiName.Length == 0) + for (int i = 0; i < 4; i++) data[pos++] = 0; + else { + d = BitConverter.GetBytes(Char.ConvertToUtf32(v.emojiName, 0)); + for (int i = 0; i < 4; i++) data[pos++] = d[i]; + } + f.Write(data, 0, pos); } - f.Write(data, 0, pos); + f.Flush(); } - f.Flush(); } + Utils.Log("EmojisForRole: Saved " + values.Count + " tracked messages and emojis"); + } catch (Exception e) { + Utils.Log("ERROR: problems in saving the EmojiForRole file: " + e.Message); } - UtilityFunctions.Log("EmojisForRole: Saved " + values.Count + " tracked messages and emojis"); } internal bool AddRemove(DiscordMessage msg, DiscordRole role, DiscordEmoji emoji) { @@ -478,30 +527,38 @@ internal bool AddRemove(DiscordMessage msg, DiscordRole role, DiscordEmoji emoji } internal void HandleAddingEmojiForRole(ulong cId, ulong eId, string eN, DiscordUser user, ulong msgId) { - DiscordMember dm = (DiscordMember)user; - if (dm == null) return; // Not a valid member for the Guild/Context - if (values == null) return; - foreach (ReactionValue v in values) { - if (cId == v.channel && msgId == v.message && (v.emojiId == 0 && v.emojiName == "!") || (eId != 0 && v.emojiId == eId) || (eId == 0 && eN.Equals(v.emojiName))) { - if (v.dRole == null) v.dRole = dm.Guild.GetRole(v.role); - dm.GrantRoleAsync(v.dRole).Wait(); - UtilityFunctions.Log("Role " + v.dRole.Name + " was granted to " + user.Username + " by emoji " + eId); - return; + try { + DiscordMember dm = (DiscordMember)user; + if (dm == null) return; // Not a valid member for the Guild/Context + if (values == null) return; + foreach (ReactionValue v in values) { + if (cId == v.channel && msgId == v.message && (v.emojiId == 0 && v.emojiName == "!") || (eId != 0 && v.emojiId == eId) || (eId == 0 && eN.Equals(v.emojiName))) { + if (v.dRole == null) v.dRole = dm.Guild.GetRole(v.role); + dm.GrantRoleAsync(v.dRole).Wait(); + Utils.Log("Role " + v.dRole.Name + " was granted to " + user.Username + " by emoji " + eId); + return; + } } + } catch (Exception e) { + Utils.Log("ERROR: problems in HandleAddingEmojiForRole: " + e.Message); } } internal void HandleRemovingEmojiForRole(ulong cId, ulong eId, string eN, DiscordUser user, ulong msgId) { - DiscordMember dm = (DiscordMember)user; - if (dm == null) return; // Not a valid member for the Guild/Context - if (values == null) return; - foreach (ReactionValue v in values) { - if (cId == v.channel && msgId == v.message && (v.emojiId == 0 && v.emojiName == "!") || (eId != 0 && v.emojiId == eId) || (eId == 0 && eN.Equals(v.emojiName))) { - if (v.dRole == null) v.dRole = dm.Guild.GetRole(v.role); - dm.RevokeRoleAsync(v.dRole).Wait(); - UtilityFunctions.Log("Role " + v.dRole.Name + " was removed from " + user.Username + " by emoji " + eId); - return; + try { + DiscordMember dm = (DiscordMember)user; + if (dm == null) return; // Not a valid member for the Guild/Context + if (values == null) return; + foreach (ReactionValue v in values) { + if (cId == v.channel && msgId == v.message && (v.emojiId == 0 && v.emojiName == "!") || (eId != 0 && v.emojiId == eId) || (eId == 0 && eN.Equals(v.emojiName))) { + if (v.dRole == null) v.dRole = dm.Guild.GetRole(v.role); + dm.RevokeRoleAsync(v.dRole).Wait(); + Utils.Log("Role " + v.dRole.Name + " was removed from " + user.Username + " by emoji " + eId); + return; + } } + } catch (Exception e) { + Utils.Log("ERROR: problems in HandleRemovingEmojiForRole: " + e.Message); } } diff --git a/UPBot Code/Actions/MembersTracking.cs b/UPBot Code/Actions/MembersTracking.cs index 4939542..0149868 100644 --- a/UPBot Code/Actions/MembersTracking.cs +++ b/UPBot Code/Actions/MembersTracking.cs @@ -9,6 +9,7 @@ public class MembersTracking { static DiscordChannel trackChannel = null; public static async Task DiscordMemberRemoved(DiscordClient client, DSharpPlus.EventArgs.GuildMemberRemoveEventArgs args) { + try{ if (tracking == null) tracking = new Dictionary(); if (trackChannel == null) trackChannel = args.Guild.GetChannel(831186370445443104ul); @@ -16,54 +17,65 @@ public static async Task DiscordMemberRemoved(DiscordClient client, DSharpPlus.E tracking.Remove(args.Member.Id); string msg = "User " + args.Member.DisplayName + " did a kiss and go."; await trackChannel.SendMessageAsync(msg); - UtilityFunctions.Log(msg); + Utils.Log(msg); } else { - string msgC = UtilityFunctions.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " left on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + args.Guild.MemberCount + " memebrs total)"; + string msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.KO) + " User " + args.Member.Mention + " left on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + args.Guild.MemberCount + " memebrs total)"; string msgL = "- User " + args.Member.DisplayName + " left on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + args.Guild.MemberCount + " memebrs total)"; await trackChannel.SendMessageAsync(msgC); - UtilityFunctions.Log(msgL); + Utils.Log(msgL); + } + } catch (Exception ex) { + Utils.Log("Error in DiscordMemberRemoved: " + ex.Message); } await Task.Delay(10); } public static async Task DiscordMemberAdded(DiscordClient client, DSharpPlus.EventArgs.GuildMemberAddEventArgs args) { + try{ if (tracking == null) tracking = new Dictionary(); if (trackChannel == null) trackChannel = args.Guild.GetChannel(831186370445443104ul); tracking[args.Member.Id] = DateTime.Now; _ = SomethingAsync(args.Member.Id, args.Member.DisplayName, args.Member.Mention, args.Guild.MemberCount); + } catch (Exception ex) { + Utils.Log("Error in DiscordMemberAdded: " + ex.Message); + } await Task.Delay(10); } public static async Task DiscordMemberUpdated(DiscordClient client, DSharpPlus.EventArgs.GuildMemberUpdateEventArgs args) { - if (tracking == null) tracking = new Dictionary(); - if (trackChannel == null) trackChannel = args.Guild.GetChannel(831186370445443104ul); + try { + if (tracking == null) tracking = new Dictionary(); + if (trackChannel == null) trackChannel = args.Guild.GetChannel(831186370445443104ul); - IReadOnlyList rolesBefore = args.RolesBefore; - IReadOnlyList rolesAfter = args.RolesAfter; - List rolesAdded = new List(); - // Changed role? - foreach (DiscordRole r1 in rolesAfter) { - bool addedRole = true; - foreach (DiscordRole r2 in rolesBefore) { - if (r1.Equals(r2)) { - addedRole = false; + IReadOnlyList rolesBefore = args.RolesBefore; + IReadOnlyList rolesAfter = args.RolesAfter; + List rolesAdded = new List(); + // Changed role? + foreach (DiscordRole r1 in rolesAfter) { + bool addedRole = true; + foreach (DiscordRole r2 in rolesBefore) { + if (r1.Equals(r2)) { + addedRole = false; + } } + if (addedRole) rolesAdded.Add(r1); } - if (addedRole) rolesAdded.Add(r1); - } - string msgC; - string msgL; - if (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 (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.SendMessageAsync(msgC); + Utils.Log(msgL); } - await trackChannel.SendMessageAsync(msgC); - UtilityFunctions.Log(msgL); + } catch (Exception ex) { + Utils.Log("Error in DiscordMemberUpdated: " + ex.Message); } await Task.Delay(10); @@ -73,10 +85,10 @@ public static async Task DiscordMemberUpdated(DiscordClient client, DSharpPlus.E static async Task SomethingAsync(ulong id, string name, string mention, int numMembers) { await Task.Delay(25000); if (tracking.ContainsKey(id)) { - string msgC = UtilityFunctions.GetEmojiSnowflakeID(EmojiEnum.OK) + " User " + mention + " joined on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + numMembers + " memebrs total)"; + string msgC = Utils.GetEmojiSnowflakeID(EmojiEnum.OK) + " User " + mention + " joined on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + numMembers + " memebrs total)"; string msgL = "+ User " + name + " joined on " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss") + " (" + numMembers + " memebrs total)"; await trackChannel.SendMessageAsync(msgC); - UtilityFunctions.Log(msgL); + Utils.Log(msgL); tracking.Remove(id); } } diff --git a/UPBot Code/Commands/BannedWords.cs b/UPBot Code/Commands/BannedWords.cs index 257e87e..63cca44 100644 --- a/UPBot Code/Commands/BannedWords.cs +++ b/UPBot Code/Commands/BannedWords.cs @@ -22,7 +22,7 @@ public class BannedWords : BaseCommandModule { public static void Init() { bannedWords = new List(); - string path = UtilityFunctions.ConstructPath(directoryName, "BannedWords", ".txt"); + string path = Utils.ConstructPath(directoryName, "BannedWords", ".txt"); if (!File.Exists(path)) return; string[] all = File.ReadAllLines(path); foreach (string line in all) { @@ -37,7 +37,7 @@ public static void Init() { [Description("To handle banned words. It can be done only by Mods and Helpers")] [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only public async Task BannedWordsCommand(CommandContext ctx) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); await ctx.Channel.SendMessageAsync("Use the commands `list`, `add`, and `remove` to handle banned words."); } @@ -45,7 +45,7 @@ public async Task BannedWordsCommand(CommandContext ctx) { [Description("To handle banned words. It can be done only by Mods and Helpers")] [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only public async Task BannedWordsCommand(CommandContext ctx, [Description("Command to use (list, add, remove)")] string command) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); await HandleListOfBannedWords(ctx, command); } @@ -53,76 +53,81 @@ public async Task BannedWordsCommand(CommandContext ctx, [Description("Command t [Description("To handle banned words. It can be done only by Mods and Helpers")] [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only public async Task BannedWordsCommand(CommandContext ctx, [Description("Command to use (list, add, remove)")] string command, [Description("The word to add or remove (not used when listing)")] string word) { - UtilityFunctions.LogUserCommand(ctx); - Task msg = await HandleAddRemoveOfBannedWords(ctx, command, word); - await Task.Delay(5000); - await msg.Result.DeleteAsync(); - await Task.Delay(1000); - await ctx.Message.DeleteAsync(); - + Utils.LogUserCommand(ctx); + Task msg = HandleAddRemoveOfBannedWords(ctx, command, word).Result; + Utils.DeleteDelayed(30, msg.Result).Wait(); + await Utils.DeleteDelayed(10, ctx.Message); } private async Task> HandleListOfBannedWords(CommandContext ctx, string command) { - if (command.ToLowerInvariant() != "list") return ctx.Channel.SendMessageAsync("Use: list, add, or remove."); - else if (bannedWords == null || bannedWords.Count == 0) return ctx.Channel.SendMessageAsync("There are no banned words I am aware of."); - else { - string message = "I have " + bannedWords.Count + " banned word" + (bannedWords.Count == 1 ? "" : "s") + ":\n"; - for (int i = 0; i < bannedWords.Count; i++) { - message += bannedWords[i].word + " (" + GetUserName(bannedWords[i].creator, ctx) + " " + bannedWords[i].date.ToString("yyyy/MM/dd") + ")"; - if (i < bannedWords.Count - 1) message += ",\n"; + try { + if (command.ToLowerInvariant() != "list") return ctx.Channel.SendMessageAsync("Use: list, add, or remove."); + else if (bannedWords == null || bannedWords.Count == 0) return ctx.Channel.SendMessageAsync("There are no banned words I am aware of."); + else { + string message = "I have " + bannedWords.Count + " banned word" + (bannedWords.Count == 1 ? "" : "s") + ":\n"; + for (int i = 0; i < bannedWords.Count; i++) { + message += bannedWords[i].word + " (" + GetUserName(bannedWords[i].creator, ctx) + " " + bannedWords[i].date.ToString("yyyy/MM/dd") + ")"; + if (i < bannedWords.Count - 1) message += ",\n"; + } + await Task.Delay(10); + return ctx.Channel.SendMessageAsync(message); } - await Task.Delay(10); - return ctx.Channel.SendMessageAsync(message); + } catch (Exception ex) { + return ctx.RespondAsync(Utils.GenerateErrorAnswer("BannedWords.List", ex)); } } private async Task> HandleAddRemoveOfBannedWords(CommandContext ctx, string command, string word) { - await Task.Delay(10); - if (command.ToLowerInvariant() == "add") { - word = word.Trim(' ', '\r', '\n').ToLowerInvariant(); - if (string.IsNullOrWhiteSpace(word) || !valid.IsMatch(word)) return ctx.Channel.SendMessageAsync("Not a valid word"); - if (bannedWords == null) bannedWords = new List(); - // Do we have it? - foreach (BannedWord bw in bannedWords) { - if (bw.word.Equals(word)) { - await ctx.Message.CreateReactionAsync(UtilityFunctions.GetEmoji(EmojiEnum.KO)); - return ctx.Channel.SendMessageAsync("The word \"" + word + "\" is already in the list."); + try { + await Task.Delay(10); + if (command.ToLowerInvariant() == "add") { + word = word.Trim(' ', '\r', '\n').ToLowerInvariant(); + if (string.IsNullOrWhiteSpace(word) || !valid.IsMatch(word)) return ctx.Channel.SendMessageAsync("Not a valid word"); + if (bannedWords == null) bannedWords = new List(); + // Do we have it? + foreach (BannedWord bw in bannedWords) { + if (bw.word.Equals(word)) { + await ctx.Message.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.KO)); + return ctx.Channel.SendMessageAsync("The word \"" + word + "\" is already in the list."); + } } - } - BannedWord w = new BannedWord(word, ctx.Message.Author.Id); - bannedWords.Add(w); - bannedWords.Sort((a, b) => { return a.word.CompareTo(b.word); }); - SaveWord(w); + BannedWord w = new BannedWord(word, ctx.Message.Author.Id); + bannedWords.Add(w); + bannedWords.Sort((a, b) => { return a.word.CompareTo(b.word); }); + SaveWord(w); - await ctx.Message.CreateReactionAsync(UtilityFunctions.GetEmoji(EmojiEnum.OK)); - return ctx.Channel.SendMessageAsync("The word \"" + word + "\" has been added."); - } - else if (command.ToLowerInvariant() == "remove") { - word = word.Trim(' ', '\r', '\n').ToLowerInvariant(); - if (string.IsNullOrWhiteSpace(word) || !Regex.IsMatch(word, @"^[a-zA-Z0-9]+$")) return ctx.Channel.SendMessageAsync("Not a valid word"); - if (bannedWords == null) bannedWords = new List(); - // Do we have it? - BannedWord found = null; - foreach (BannedWord bw in bannedWords) { - if (bw.word.Equals(word)) { - found = bw; - break; - } + await ctx.Message.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.OK)); + return ctx.Channel.SendMessageAsync("The word \"" + word + "\" has been added."); } - if (found == null) { - await ctx.Message.CreateReactionAsync(UtilityFunctions.GetEmoji(EmojiEnum.KO)); - return ctx.Channel.SendMessageAsync("The word \"" + word + "\" is not in the list."); + else if (command.ToLowerInvariant() == "remove") { + word = word.Trim(' ', '\r', '\n').ToLowerInvariant(); + if (string.IsNullOrWhiteSpace(word) || !Regex.IsMatch(word, @"^[a-zA-Z0-9]+$")) return ctx.Channel.SendMessageAsync("Not a valid word"); + if (bannedWords == null) bannedWords = new List(); + // Do we have it? + BannedWord found = null; + foreach (BannedWord bw in bannedWords) { + if (bw.word.Equals(word)) { + found = bw; + break; + } + } + if (found == null) { + await ctx.Message.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.KO)); + return ctx.Channel.SendMessageAsync("The word \"" + word + "\" is not in the list."); + } + bannedWords.Remove(found); + SaveList(); + await ctx.Message.CreateReactionAsync(Utils.GetEmoji(EmojiEnum.OK)); + return ctx.Channel.SendMessageAsync("The word \"" + word + "\" has been removed."); } - bannedWords.Remove(found); - SaveList(); - await ctx.Message.CreateReactionAsync(UtilityFunctions.GetEmoji(EmojiEnum.OK)); - return ctx.Channel.SendMessageAsync("The word \"" + word + "\" has been removed."); + else return ctx.Channel.SendMessageAsync("Use: add or remove and then the word."); + } catch (Exception ex) { + return ctx.RespondAsync(Utils.GenerateErrorAnswer("BannedWords.Handle", ex)); } - else return ctx.Channel.SendMessageAsync("Use: add or remove and then the word."); } void SaveWord(BannedWord w) { - string path = UtilityFunctions.ConstructPath(directoryName, "BannedWords", ".txt"); + string path = Utils.ConstructPath(directoryName, "BannedWords", ".txt"); if (!File.Exists(path)) File.CreateText(path); try { using (StreamWriter sw = File.AppendText(path)) { @@ -130,17 +135,17 @@ void SaveWord(BannedWord w) { sw.FlushAsync(); } } catch (Exception e) { - UtilityFunctions.Log(e.Message); + Utils.Log(e.Message); } } void SaveList() { - string path = UtilityFunctions.ConstructPath(directoryName, "BannedWords", ".txt"); + string path = Utils.ConstructPath(directoryName, "BannedWords", ".txt"); if (File.Exists(path)) { try { File.Delete(path); } catch (Exception e) { - UtilityFunctions.Log(e.Message); + Utils.Log(e.Message); return; } } @@ -152,7 +157,7 @@ void SaveList() { } } } catch (Exception e) { - UtilityFunctions.Log(e.Message); + Utils.Log(e.Message); } } @@ -199,33 +204,36 @@ async Task GetUserNameFromDiscord(ulong userId, CommandContext ctx) } internal static async Task CheckMessage(DiscordClient client, MessageCreateEventArgs args) { - // Who is the author? If the bot or a mod then ignore - if (args.Author.Equals(client.CurrentUser)) return; - DiscordUser user = args.Author; - DiscordGuild guild = await client.GetGuildAsync((ulong)args.Message.Channel.GuildId); - DiscordMember member; try { - member = await guild.GetMemberAsync(user.Id); - } catch (Exception) { - return; - } - foreach (DiscordRole role in member.Roles) { - if (role.Id == 831050318171078718ul /* Helper */ || role.Id == 830901743624650783ul /* Mod */ || role.Id == 830901562960117780ul /* Owner */) return; - } + // Who is the author? If the bot or a mod then ignore + if (args.Author.Equals(client.CurrentUser)) return; + DiscordUser user = args.Author; + DiscordGuild guild = await client.GetGuildAsync((ulong)args.Message.Channel.GuildId); + DiscordMember member; + try { + member = await guild.GetMemberAsync(user.Id); + } catch (Exception) { + return; + } + foreach (DiscordRole role in member.Roles) { + if (role.Id == 831050318171078718ul /* Helper */ || role.Id == 830901743624650783ul /* Mod */ || role.Id == 830901562960117780ul /* Owner */) return; + } - string msg = args.Message.Content.ToLowerInvariant(); - foreach (BannedWord w in bannedWords) { - int pos = msg.IndexOf(w.word); - if (pos == -1) continue; - if (pos > 0 && letters.IsMatch(msg[pos - 1].ToString())) continue; - if (pos + w.word.Length < msg.Length && letters.IsMatch(msg[pos + w.word.Length].ToString())) continue; - - UtilityFunctions.Log("Removed word \"" + w.word + "\" from " + user.Username + " in: " + msg); - DiscordMessage warning = await args.Message.Channel.SendMessageAsync("Moderate your language, " + user.Mention + "."); - await args.Message.DeleteAsync("Bad words: " + w.word); - await Task.Delay(10000); - await warning.DeleteAsync(); - return; + string msg = args.Message.Content.ToLowerInvariant(); + foreach (BannedWord w in bannedWords) { + int pos = msg.IndexOf(w.word); + if (pos == -1) continue; + if (pos > 0 && letters.IsMatch(msg[pos - 1].ToString())) continue; + if (pos + w.word.Length < msg.Length && letters.IsMatch(msg[pos + w.word.Length].ToString())) continue; + + Utils.Log("Removed word \"" + w.word + "\" from " + user.Username + " in: " + msg); + DiscordMessage warning = await args.Message.Channel.SendMessageAsync("Moderate your language, " + user.Mention + "."); + await args.Message.DeleteAsync("Bad words: " + w.word); + Utils.DeleteDelayed(10000, warning).Wait(); + return; + } + } catch (Exception ex) { + await args.Message.RespondAsync(Utils.GenerateErrorAnswer("BannedWords.CheckMessage", ex)); } } diff --git a/UPBot Code/Commands/CustomCommand.cs b/UPBot Code/Commands/CustomCommand.cs index 85c6055..413b77f 100644 --- a/UPBot Code/Commands/CustomCommand.cs +++ b/UPBot Code/Commands/CustomCommand.cs @@ -10,7 +10,7 @@ public class CustomCommand public CustomCommand(string[] names, string content) { this.Names = names; - this.FilePath = UtilityFunctions.ConstructPath(CustomCommandsService.DirectoryNameCC, names[0], ".txt"); + this.FilePath = Utils.ConstructPath(CustomCommandsService.DirectoryNameCC, names[0], ".txt"); this.Content = content; } diff --git a/UPBot Code/Commands/CustomCommandsService.cs b/UPBot Code/Commands/CustomCommandsService.cs index 9454abe..79568f7 100644 --- a/UPBot Code/Commands/CustomCommandsService.cs +++ b/UPBot Code/Commands/CustomCommandsService.cs @@ -20,7 +20,7 @@ public class CustomCommandsService : BaseCommandModule internal const string DirectoryNameCC = "CustomCommands"; [Command("newcc")] - [Aliases("createcc", "addcc", "ccadd", "cccreate")] + [Aliases("createcc", "addcc", "ccadd", "cccreate", "ccnew")] [Description("**Create** a new Custom Command (so-called 'CC') with a specified name and all aliases if desired " + "(no duplicate alias allowed).\nAfter doing this, the bot will ask you to input the content, which will " + "be displayed once someone invokes this CC. Your entire next message will be used for the content, so " + @@ -29,12 +29,13 @@ public class CustomCommandsService : BaseCommandModule [RequireRoles(RoleCheckMode.Any, "Mod", "Owner")] // Restrict access to users with the "Mod" or "Owner" role only public async Task CreateCommand(CommandContext ctx, [Description("A 'list' of all aliases. The first term is the **main name**, the other ones, separated by a space, are aliases")] params string[] names) { - names = names.Distinct().ToArray(); + Utils.LogUserCommand(ctx); + names = names.Distinct().ToArray(); foreach (var name in names) { if (DiscordClient.GetCommandsNext().RegisteredCommands.ContainsKey(name)) // Check if there is a command with one of the names already { - await UtilityFunctions.ErrorCallback(CommandErrors.CommandExists, ctx, name); + await Utils.ErrorCallback(CommandErrors.CommandExists, ctx, name); return; } @@ -42,7 +43,7 @@ public async Task CreateCommand(CommandContext ctx, [Description("A 'list' of al { if (cmd.Names.Contains(name)) // Check if there is already a CC with one of the names { - await UtilityFunctions.ErrorCallback(CommandErrors.CommandExists, ctx, name); + await Utils.ErrorCallback(CommandErrors.CommandExists, ctx, name); return; } } @@ -54,7 +55,7 @@ public async Task CreateCommand(CommandContext ctx, [Description("A 'list' of al await WriteToFile(command); string embedMessage = $"CC {names[0]} successfully created and saved!"; - await UtilityFunctions.BuildEmbedAndExecute("Success", embedMessage, UtilityFunctions.Green, ctx, false); + await Utils.BuildEmbedAndExecute("Success", embedMessage, Utils.Green, ctx, false); } [Command("ccdel")] @@ -65,7 +66,8 @@ public async Task CreateCommand(CommandContext ctx, [Description("A 'list' of al [RequireRoles(RoleCheckMode.Any, "Mod", "Owner")] // Restrict access to users with the "Mod" or "Owner" role only public async Task DeleteCommand(CommandContext ctx, [Description("Main name of the CC you want to delete")] string name) { - string filePath = UtilityFunctions.ConstructPath(DirectoryNameCC, name, ".txt"); + Utils.LogUserCommand(ctx); + string filePath = Utils.ConstructPath(DirectoryNameCC, name, ".txt"); if (File.Exists(filePath)) { File.Delete(filePath); @@ -73,7 +75,7 @@ public async Task DeleteCommand(CommandContext ctx, [Description("Main name of t Commands.Remove(cmd); string embedMessage = $"CC {name} successfully deleted!"; - await UtilityFunctions.BuildEmbedAndExecute("Success", embedMessage, UtilityFunctions.Green, ctx, true); + await Utils.BuildEmbedAndExecute("Success", embedMessage, Utils.Green, ctx, true); } } @@ -85,7 +87,8 @@ public async Task DeleteCommand(CommandContext ctx, [Description("Main name of t [RequireRoles(RoleCheckMode.Any, "Mod", "Owner")] // Restrict access to users with the "Mod" or "Owner" role only public async Task EditCommand(CommandContext ctx, [Description("Main name of the CC you want to edit")] string name) { - string filePath = UtilityFunctions.ConstructPath(DirectoryNameCC, name, ".txt"); + Utils.LogUserCommand(ctx); + string filePath = Utils.ConstructPath(DirectoryNameCC, name, ".txt"); if (File.Exists(filePath)) { string content = await WaitForContent(ctx, name); @@ -104,10 +107,10 @@ public async Task EditCommand(CommandContext ctx, [Description("Main name of the command.EditCommand(content); string embedMessage = $"CC **{name}** successfully edited!"; - await UtilityFunctions.BuildEmbedAndExecute("Success", embedMessage, UtilityFunctions.Green, ctx, false); + await Utils.BuildEmbedAndExecute("Success", embedMessage, Utils.Green, ctx, false); } else - await UtilityFunctions.ErrorCallback(CommandErrors.MissingCommand, ctx); + await Utils.ErrorCallback(CommandErrors.MissingCommand, ctx); } [Command("cceditname")] @@ -121,14 +124,15 @@ public async Task EditCommand(CommandContext ctx, [Description("Main name of the "of the CC whose name you want to edit, the **SECOND** term " + "is the new **main name** and all the other terms are new aliases")] params string[] names) { - names = names.Distinct().ToArray(); + Utils.LogUserCommand(ctx); + names = names.Distinct().ToArray(); if (names.Length < 2) { - await UtilityFunctions.ErrorCallback(CommandErrors.InvalidParams, ctx); + await Utils.ErrorCallback(CommandErrors.InvalidParams, ctx); return; } - string filePath = UtilityFunctions.ConstructPath(DirectoryNameCC, names[0], ".txt"); + string filePath = Utils.ConstructPath(DirectoryNameCC, names[0], ".txt"); if (File.Exists(filePath)) { if (TryGetCommand(names[0], out CustomCommand command)) @@ -143,7 +147,7 @@ public async Task EditCommand(CommandContext ctx, [Description("Main name of the content += c + System.Environment.NewLine; } - string newPath = UtilityFunctions.ConstructPath(DirectoryNameCC, names[1], ".txt"); + string newPath = Utils.ConstructPath(DirectoryNameCC, names[1], ".txt"); File.Move(filePath, newPath); using (StreamWriter sw = File.CreateText(newPath)) { @@ -152,10 +156,10 @@ public async Task EditCommand(CommandContext ctx, [Description("Main name of the } string embedDescription = "The CC names have been successfully edited."; - await UtilityFunctions.BuildEmbedAndExecute("Success", embedDescription, UtilityFunctions.Green, ctx, false); + await Utils.BuildEmbedAndExecute("Success", embedDescription, Utils.Green, ctx, false); } else - await UtilityFunctions.ErrorCallback(CommandErrors.MissingCommand, ctx); + await Utils.ErrorCallback(CommandErrors.MissingCommand, ctx); } [Command("cclist")] @@ -163,9 +167,10 @@ public async Task EditCommand(CommandContext ctx, [Description("Main name of the [Description("Get a list of all Custom Commands (CC's).")] public async Task ListCC(CommandContext ctx) { - if (Commands.Count <= 0) + Utils.LogUserCommand(ctx); + if (Commands.Count <= 0) { - await UtilityFunctions.ErrorCallback(CommandErrors.NoCustomCommands, ctx); + await Utils.ErrorCallback(CommandErrors.NoCustomCommands, ctx); return; } @@ -176,7 +181,7 @@ public async Task ListCC(CommandContext ctx) allCommands += $"- {cmd.Names[0]} ({(cmd.Names.Length > 1 ? string.Join(", ", cmd.Names.Skip(1)) : string.Empty)}){System.Environment.NewLine}"; } - await UtilityFunctions.BuildEmbedAndExecute("CC List", allCommands, UtilityFunctions.Yellow, ctx, true); + await Utils.BuildEmbedAndExecute("CC List", allCommands, Utils.Yellow, ctx, true); } internal static async Task LoadCustomCommands() @@ -229,7 +234,7 @@ private async Task WriteToFile(CustomCommand command) private async Task WaitForContent(CommandContext ctx, string name) { string embedMessage = $"Please input the content of the CC **{name}** in one single message. Your next message will count as the content."; - await UtilityFunctions.BuildEmbedAndExecute("Waiting for interaction", embedMessage, UtilityFunctions.LightBlue, ctx, true); + await Utils.BuildEmbedAndExecute("Waiting for interaction", embedMessage, Utils.LightBlue, ctx, true); string content = string.Empty; await ctx.Message.GetNextMessageAsync(m => diff --git a/UPBot Code/Commands/DebugCommand.cs b/UPBot Code/Commands/DebugCommand.cs deleted file mode 100644 index 06b964d..0000000 --- a/UPBot Code/Commands/DebugCommand.cs +++ /dev/null @@ -1,26 +0,0 @@ -ο»Ώusing DSharpPlus; -using DSharpPlus.CommandsNext; -using DSharpPlus.CommandsNext.Attributes; -using DSharpPlus.Entities; -using System.Threading.Tasks; - -/// -/// Debug command to quickly test some new stuff -/// author: CPU -/// -public class DebugCommand : BaseCommandModule { - - [Command("qwe")] - [Description("This is a command just to quickly debug stuff in development")] - [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission - [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only - public async Task DoDebug(CommandContext ctx) { // Refactors the previous post, if it is code - UtilityFunctions.LogUserCommand(ctx); - DiscordMessage msg = await ctx.Channel.SendMessageAsync("Test message"); - - DiscordEmoji emoji = UtilityFunctions.GetEmoji(EmojiEnum.Godot); - await msg.CreateReactionAsync(emoji); - - await ctx.Message.RespondAsync("Done"); - } -} diff --git a/UPBot Code/Commands/Delete.cs b/UPBot Code/Commands/Delete.cs index 084c6e0..a45c7cc 100644 --- a/UPBot Code/Commands/Delete.cs +++ b/UPBot Code/Commands/Delete.cs @@ -1,4 +1,5 @@ -ο»Ώusing System.Collections.Generic; +ο»Ώusing System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using DSharpPlus; @@ -11,96 +12,96 @@ /// or the last x messages of a specific user /// author: Duck /// -public class Delete : BaseCommandModule -{ - private const int MessageLimit = 50; - private const string CallbackLimitExceeded = ", since you can't delete more than 50 messages at a time."; +public class Delete : BaseCommandModule { + private const int MessageLimit = 50; + private const string CallbackLimitExceeded = ", since you can't delete more than 50 messages at a time."; - /// - /// Delete the last x messages of any user - /// - [Command("delete")] - [Aliases("clear", "purge")] - [Description("Deletes the last x messages in the channel, the command was invoked in (e.g. `\\delete 10`)." + - "\nIt contains an overload to delete the last x messages of a specified user (e.g. `\\delete @User 10`)." + - "\nThis command can only be invoked by a Helper or Mod.")] - [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission - [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only - public async Task DeleteCommand(CommandContext ctx, [Description("How many messages should be deleted?")] int count) - { - UtilityFunctions.LogUserCommand(ctx); - if (count <= 0) - { - await UtilityFunctions.ErrorCallback(CommandErrors.InvalidParamsDelete, ctx, count); - return; - } + /// + /// Delete the last x messages of any user + /// + [Command("delete")] + [Aliases("clear", "purge")] + [Description("Deletes the last x messages in the channel, the command was invoked in (e.g. `\\delete 10`)." + + "\nIt contains an overload to delete the last x messages of a specified user (e.g. `\\delete @User 10`)." + + "\nThis command can only be invoked by a Helper or Mod.")] + [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission + [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only + public async Task DeleteCommand(CommandContext ctx, [Description("How many messages should be deleted?")] int count) { + Utils.LogUserCommand(ctx); + if (count <= 0) { + await Utils.ErrorCallback(CommandErrors.InvalidParamsDelete, ctx, count); + return; + } + + bool limitExceeded = CheckLimit(count); - bool limitExceeded = CheckLimit(count); + var messages = ctx.Channel.GetMessagesAsync(count + 1).Result; + await DeleteMessages(ctx.Message, messages); - var messages = ctx.Channel.GetMessagesAsync(count + 1).Result; - await DeleteMessages(ctx, messages); + await Success(ctx, limitExceeded, count); + } - await Success(ctx, limitExceeded, count); + /// + /// Delete the last x messages of the specified user + /// + [Command("delete")] + [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission + [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only + public async Task DeleteCommand(CommandContext ctx, [Description("Whose last x messages should get deleted?")] DiscordMember targetUser, + [Description("How many messages should get deleted?")] int count) { + Utils.LogUserCommand(ctx); + if (count <= 0) { + await Utils.ErrorCallback(CommandErrors.InvalidParamsDelete, ctx, count); + return; } - /// - /// Delete the last x messages of the specified user - /// - [Command("delete")] - [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission - [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only - public async Task DeleteCommand(CommandContext ctx, [Description("Whose last x messages should get deleted?")]DiscordMember targetUser, - [Description("How many messages should get deleted?")] int count) - { - UtilityFunctions.LogUserCommand(ctx); - if (count <= 0) - { - await UtilityFunctions.ErrorCallback(CommandErrors.InvalidParamsDelete, ctx, count); - return; - } + bool limitExceeded = CheckLimit(count); - bool limitExceeded = CheckLimit(count); + var allMessages = ctx.Channel.GetMessagesAsync().Result; // Get last 100 messages + var userMessages = allMessages.Where(x => x.Author == targetUser).Take(count + 1); + await DeleteMessages(ctx.Message, userMessages); - var allMessages = ctx.Channel.GetMessagesAsync().Result; // Get last 100 messages - var userMessages = allMessages.Where(x => x.Author == targetUser).Take(count + 1); - await DeleteMessages(ctx, userMessages); + await Success(ctx, limitExceeded, count, targetUser); + } - await Success(ctx, limitExceeded, count, targetUser); + /// + /// The core-process of deleting the messages + /// + public async Task DeleteMessages(DiscordMessage request, IEnumerable messages) { + try{ + List toDelete = new List(); + foreach (DiscordMessage m in messages) { + if (m != request) toDelete.Add(m); } - - /// - /// The core-process of deleting the messages - /// - public async Task DeleteMessages(CommandContext ctx, IEnumerable messages) - { - foreach (DiscordMessage m in messages) - { - if (m != ctx.Message) - await m.DeleteAsync(); - } + await request.Channel.DeleteMessagesAsync(toDelete); + } catch (Exception ex) { + await request.RespondAsync(Utils.GenerateErrorAnswer("DeleteMessages", ex)); } - /// - /// Will be called at the end of every execution of this command and tells the user that the execution succeeded - /// including a short summary of the command (how many messages, by which user etc.) - /// - private async Task Success(CommandContext ctx, bool limitExceeded, int count, DiscordMember targetUser = null) - { - string mentionUserStr = targetUser == null ? string.Empty : $"by '{targetUser.DisplayName}'"; - string overLimitStr = limitExceeded ? CallbackLimitExceeded : string.Empty; - string messagesLiteral = UtilityFunctions.PluralFormatter(count, "message", "messages"); - string hasLiteral = UtilityFunctions.PluralFormatter(count, "has", "have"); + } - await ctx.Message.DeleteAsync(); - string embedMessage = $"The last {count} {messagesLiteral} {mentionUserStr} {hasLiteral} been successfully deleted{overLimitStr}."; + /// + /// Will be called at the end of every execution of this command and tells the user that the execution succeeded + /// including a short summary of the command (how many messages, by which user etc.) + /// + private async Task Success(CommandContext ctx, bool limitExceeded, int count, DiscordMember targetUser = null) { + try{ + string mentionUserStr = targetUser == null ? string.Empty : $"by '{targetUser.DisplayName}'"; + string overLimitStr = limitExceeded ? CallbackLimitExceeded : string.Empty; + string messagesLiteral = Utils.PluralFormatter(count, "message", "messages"); + string hasLiteral = Utils.PluralFormatter(count, "has", "have"); - var message = await UtilityFunctions.BuildEmbedAndExecute("Success", embedMessage, UtilityFunctions.Green, ctx, true); - await Task.Delay(10_000); - await message.DeleteAsync(); - } + await ctx.Message.DeleteAsync(); + string embedMessage = $"The last {count} {messagesLiteral} {mentionUserStr} {hasLiteral} been successfully deleted{overLimitStr}."; - private bool CheckLimit(int count) - { - return count > MessageLimit; + var message = await Utils.BuildEmbedAndExecute("Success", embedMessage, Utils.Green, ctx, true); + await Utils.DeleteDelayed(10, message); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("Delete", ex)); } + } + + private bool CheckLimit(int count) { + return count > MessageLimit; + } } \ No newline at end of file diff --git a/UPBot Code/Commands/Game.cs b/UPBot Code/Commands/Game.cs index a65db33..7006266 100644 --- a/UPBot Code/Commands/Game.cs +++ b/UPBot Code/Commands/Game.cs @@ -14,7 +14,7 @@ public class GameModule : BaseCommandModule [Command("game")] public async Task GameCommand(CommandContext ctx) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); StringBuilder sb = new StringBuilder("Available game commmands\n"); sb.AppendLine("========================"); sb.AppendLine(String.Format("{0, -10}: {1}", "bool", "True or False")); @@ -26,21 +26,21 @@ public async Task GameCommand(CommandContext ctx) [Command("bool")] public async Task BoolCommand(CommandContext ctx) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); await PlayBool(ctx); } [Command("rps")] public async Task RPSCommand(CommandContext ctx, string kind) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); await PlayRockPaperScissors(ctx, kind); } [Command("rps")] public async Task RPSCommand(CommandContext ctx) { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); await PlayRockPaperScissors(ctx, null); } diff --git a/UPBot Code/Commands/HelpLanguages.cs b/UPBot Code/Commands/HelpLanguages.cs index af8c779..58f8537 100644 --- a/UPBot Code/Commands/HelpLanguages.cs +++ b/UPBot Code/Commands/HelpLanguages.cs @@ -47,17 +47,18 @@ public async Task ErrorMessage(CommandContext ctx) { string title = "Help Language - How To Use"; DiscordMember member = ctx.Member; - string description = member.Mention + " , if you want to get video course about specific language type: `\\helplanguage video C#`" + - " \nIf you want to get full online course about specific language type: \n`\\helplanguage course C#`" + + string description = member.Mention + " , if you want to get video course about specific language type: `helplanguage video C#`" + + " \nIf you want to get full online course about specific language type: \n`helplanguage course C#`" + " \nAvailable languages: `ะก#, C++, Python, JavaScript, Java`"; - await UtilityFunctions.BuildEmbedAndExecute(title, description, UtilityFunctions.Red, ctx, true); + await Utils.BuildEmbedAndExecute(title, description, Utils.Red, ctx, true); } [Command("helplanguage")] - [Description("Gives good tutorials on specific language.\n**Usage:** `\\helplanguage language`")] + [Description("Gives good tutorials on specific language.\n**Usage**: `helplanguage language`")] public async Task HelpCommand(CommandContext ctx, [Description("Choose what you want video or course on specific language.")] string typeOfHelp, [Description("As string `` put the name of language that you want to learn")] string lang) // C# { - UtilityFunctions.LogUserCommand(ctx); + Utils.LogUserCommand(ctx); + try { lang = NormalizeLanguage(lang); if (lang == null) @@ -73,6 +74,9 @@ public async Task HelpCommand(CommandContext ctx, [Description("Choose what you bool course = typeOfHelp.ToLowerInvariant() != "video"; await GenerateHelpfulAnswer(ctx, lang, course); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("WhoIs", ex)); + } } private string NormalizeLanguage(string language) { @@ -100,11 +104,10 @@ private string NormalizeLanguage(string language) { default: return char.ToUpperInvariant(language[0]) + language.Substring(1); } - - //return language; } private async Task GenerateHelpfulAnswer(CommandContext ctx, string language, bool isCourse) { + try{ DiscordMember member = ctx.Member; ulong memberId = member.Id; @@ -133,12 +136,14 @@ private async Task GenerateHelpfulAnswer(CommandContext ctx, string language, bo string link = isCourse ? languages[language].CourseLink :languages[language].VideoLink; string msg = helpfulAnswers[lastRequest.Num]; - msg = msg.Replace("$$$", member.DisplayName).Replace("@@@", member.Mention) - .Replace("///", link); + msg = msg.Replace("$$$", member.DisplayName).Replace("@@@", member.Mention).Replace("///", link); if (isCourse) msg = msg.Replace("video", "course"); - await UtilityFunctions.BuildEmbedAndExecute(title, msg, languages[language].Color, ctx, true); + await Utils.BuildEmbedAndExecute(title, msg, languages[language].Color, ctx, true); + } catch (Exception ex) { + await ctx.RespondAsync(Utils.GenerateErrorAnswer("HelpLanguage", ex)); + } } private class LastRequestByMember { diff --git a/UPBot Code/Commands/Ping.cs b/UPBot Code/Commands/Ping.cs index f9b1475..96bd43f 100644 --- a/UPBot Code/Commands/Ping.cs +++ b/UPBot Code/Commands/Ping.cs @@ -14,11 +14,9 @@ public class PingModule : BaseCommandModule { private List lastRequests = null; [Command("ping")] - public async Task GreetCommand(CommandContext ctx) { - await GeneratePong(ctx); - } - [Command("upbot")] - public async Task GreetCommand2(CommandContext ctx) { + [Aliases("upbot")] + [Description("Checks if the bot is alive")] + public async Task PongCommand(CommandContext ctx) { await GeneratePong(ctx); } @@ -37,39 +35,47 @@ public async Task GreetCommand2(CommandContext ctx) { int lastGlobal = -1; Task GeneratePong(CommandContext ctx) { + Utils.LogUserCommand(ctx); + try { + + // Check if we have to initiialize our history of pings + if (lastRequests == null) lastRequests = new List(); + + // Grab the current member id + DiscordMember member = ctx.Member; + ulong memberId = member.Id; + + // Find the last request + LastRequestByMember lastRequest = null; + int annoyedLevel = 0; + foreach (LastRequestByMember lr in lastRequests) + if (lr.memberId == memberId) { + lastRequest = lr; + break; + } + if (lastRequest == null) { // No last request, create one + lastRequest = new LastRequestByMember(memberId); + lastRequests.Add(lastRequest); + } + else { + annoyedLevel = lastRequest.AddRequest(); + } + if (annoyedLevel == -1) return ctx.RespondAsync(""); // No answer - // Check if we have to initiialize our history of pings - if (lastRequests == null) lastRequests = new List(); + // Was the request already done recently? + int rnd = random.Next(0, 7); + while (rnd == lastRequest.lastRandom || rnd == lastGlobal) rnd = random.Next(0, 7); // Find one that is not the same of last one + lastRequest.lastRandom = rnd; // Record for the next time + lastGlobal = rnd; // Record for the next time + string msg = answers[annoyedLevel, rnd]; + msg = msg.Replace("$$$", member.DisplayName).Replace("@@@", member.Mention); - // Grab the current member id - DiscordMember member = ctx.Member; - ulong memberId = member.Id; - // Find the last request - LastRequestByMember lastRequest = null; - int annoyedLevel = 0; - foreach (LastRequestByMember lr in lastRequests) - if (lr.memberId == memberId) { - lastRequest = lr; - break; - } - if (lastRequest == null) { // No last request, create one - lastRequest = new LastRequestByMember(memberId); - lastRequests.Add(lastRequest); - } - else { - annoyedLevel = lastRequest.AddRequest(); + DiscordMessage answer = ctx.RespondAsync(msg).Result; + return Utils.DeleteDelayed(30, ctx.Message, answer); // We want to remove the ping and the answer after a minute + } catch (Exception ex) { + return ctx.RespondAsync(Utils.GenerateErrorAnswer("Ping", ex)); } - if (annoyedLevel == -1) return ctx.RespondAsync(""); // No answer - - // Was the request already done recently? - int rnd = random.Next(0, 7); - while (rnd == lastRequest.lastRandom || rnd == lastGlobal) rnd = random.Next(0, 7); // Find one that is not the same of last one - lastRequest.lastRandom = rnd; // Record for the next time - lastGlobal = rnd; // Record for the next time - string msg = answers[annoyedLevel, rnd]; - msg = msg.Replace("$$$", member.DisplayName).Replace("@@@", member.Mention); - return ctx.RespondAsync(msg); } const int MaxTrackedRequests = 10; diff --git a/UPBot Code/Commands/Refactor.cs b/UPBot Code/Commands/Refactor.cs index 63d05e5..86d9e12 100644 --- a/UPBot Code/Commands/Refactor.cs +++ b/UPBot Code/Commands/Refactor.cs @@ -13,19 +13,19 @@ public class Refactor : BaseCommandModule { [Command("checklanguage")] - [Description("Check what language is in the last post or in the post you replied to")] + [Description("Checks what language is in the post you replied to, or the last post of a specified user or just the last post.")] public async Task CheckLanguage(CommandContext ctx) { // Refactors the previous post, if it is code await RefactorCode(ctx, null, "best"); } [Command("checklanguage")] - [Description("Check what language is in the last post of the user")] + [Description("Checks what language is in the post you replied to, or the last post of a specified user or just the last post.")] public async Task CheckLanguage(CommandContext ctx, [Description("The user the posted the message to check")] DiscordMember member) { // Refactors the previous post, if it is code await RefactorCode(ctx, member, "best"); } [Command("reformat")] - [Description("Replace the last post of the specified user or the post you replied to with a formatted code block using the specified language")] + [Description("Replace a specified post with a reformatted code block using the specified language or the best language")] [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only public async Task RefactorCommand(CommandContext ctx) { // Refactors the previous post, if it is code @@ -36,7 +36,7 @@ public class Refactor : BaseCommandModule { [Description("Replace the last post of the specified user or the post you replied to with a formatted code block")] [RequirePermissions(Permissions.ManageMessages)] // Restrict this command to users/roles who have the "Manage Messages" permission [RequireRoles(RoleCheckMode.Any, "Helper", "Mod", "Owner")] // Restrict this command to "Helper", "Mod" and "Owner" roles only - public async Task ReformatCommand(CommandContext ctx, [Description("Force the Language to use. Use 'best' or 'Analyze' to find the best language.")] string language) { // Refactors the previous post, if it is code + public async Task ReformatCommand(CommandContext ctx, [Description("Force the Language to use. Use **Best** or **Analyze** to find the best language.")] string language) { // Refactors the previous post, if it is code await RefactorCode(ctx, null, language); } @@ -55,96 +55,100 @@ public async Task RefacReformatCommandtorCommand(CommandContext ctx, [Descriptio } private async Task> RefactorCode(CommandContext ctx, DiscordMember m, string language) { - UtilityFunctions.LogUserCommand(ctx); - DiscordChannel c = ctx.Channel; - DiscordMessage toRefactor = null; - if (ctx.Message.Reference != null) toRefactor = ctx.Message.Reference.Message; - else { - IReadOnlyList msgs = await c.GetMessagesAsync(50); - if (m == null) toRefactor = msgs[1]; + Utils.LogUserCommand(ctx); + try { + DiscordChannel c = ctx.Channel; + DiscordMessage toRefactor = null; + if (ctx.Message.Reference != null) toRefactor = ctx.Message.Reference.Message; else { - for (int i = 1; i < msgs.Count; i++) { - if (msgs[i].Author.Id.Equals(m.Id)) { - toRefactor = msgs[i]; - break; + IReadOnlyList msgs = await c.GetMessagesAsync(50); + if (m == null) toRefactor = msgs[1]; + else { + for (int i = 1; i < msgs.Count; i++) { + if (msgs[i].Author.Id.Equals(m.Id)) { + toRefactor = msgs[i]; + break; + } } } + if (toRefactor == null) return ctx.RespondAsync("Nothing to refactor found"); } - if (toRefactor == null) return ctx.RespondAsync("Nothing to refactor found"); - } - // Is the message some code? - string code = toRefactor.Content; - int weightCs = 0, weightCp = 0, weightJv = 0, weightJs = 0, weightPy = 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; + // Is the message some code? + string code = toRefactor.Content; + int weightCs = 0, weightCp = 0, weightJv = 0, weightJs = 0, weightPy = 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; + } } - } - string guessed = "no one"; - string best = ""; - EmojiEnum langEmoji = EmojiEnum.None; - int w = 0; - if (weightCs > w) { guessed = "<:csharp:831465428214743060> C#"; w = weightCs; best = "cs"; langEmoji = EmojiEnum.CSharp; } - if (weightCp > w) { guessed = "<:cpp:831465408874676273> C++"; w = weightCp; best = "cpp"; langEmoji = EmojiEnum.Cpp; } - if (weightJs > w) { guessed = "<:Javascript:876103767068647435> Javascript"; w = weightJs; best = "js"; langEmoji = EmojiEnum.Javascript; } - if (weightJv > w) { guessed = "<:java:875852276017815634> Java"; w = weightJv; best = "java"; langEmoji = EmojiEnum.Java; } - if (weightPy > w) { guessed = "<:python:831465381016895500> Python"; w = weightPy; best = "python"; langEmoji = EmojiEnum.Python; } - if (w == 0 && language == null) return ctx.RespondAsync("Nothing to reformat"); + string guessed = "no one"; + string best = ""; + EmojiEnum langEmoji = EmojiEnum.None; + int w = 0; + if (weightCs > w) { guessed = "<:csharp:831465428214743060> C#"; w = weightCs; best = "cs"; langEmoji = EmojiEnum.CSharp; } + if (weightCp > w) { guessed = "<:cpp:831465408874676273> C++"; w = weightCp; best = "cpp"; langEmoji = EmojiEnum.Cpp; } + if (weightJs > w) { guessed = "<:Javascript:876103767068647435> Javascript"; w = weightJs; best = "js"; langEmoji = EmojiEnum.Javascript; } + if (weightJv > w) { guessed = "<:java:875852276017815634> Java"; w = weightJv; best = "java"; langEmoji = EmojiEnum.Java; } + if (weightPy > w) { guessed = "<:python:831465381016895500> Python"; w = weightPy; best = "python"; langEmoji = EmojiEnum.Python; } + if (w == 0 && language == null) return ctx.RespondAsync("Nothing to reformat"); - language = NormalizeLanguage(language, best); - if (language == null) - return ctx.RespondAsync("Best guess for the language is: " + guessed + "\nC# = " + weightCs + " C++ = " + weightCp + " Java = " + weightJv + " Javascript = " + weightJs + " Python = " + weightPy); + language = NormalizeLanguage(language, best); + if (language == null) + return ctx.RespondAsync("Best guess for the language is: " + guessed + "\nC# = " + weightCs + " C++ = " + weightCp + " Java = " + weightJv + " Javascript = " + weightJs + " Python = " + weightPy); - // Remove the ``` at begin and end, if any. And the code name after initial ``` - bool deleteOrig = true; - Match codeMatch = codeBlock.Match(code); - if (codeMatch.Success) { - code = codeMatch.Groups[5].Value; - deleteOrig = string.IsNullOrWhiteSpace(codeMatch.Groups[1].Value); - } - code = code.Trim(' ', '\t', '\r', '\n'); - code = emptyLines.Replace(code, "\n"); - - if (langEmoji == EmojiEnum.CSharp || langEmoji == EmojiEnum.Cpp || langEmoji == EmojiEnum.Java || langEmoji == EmojiEnum.Javascript) code = FixIndentation(code); + // Remove the ``` at begin and end, if any. And the code name after initial ``` + bool deleteOrig = true; + Match codeMatch = codeBlock.Match(code); + if (codeMatch.Success) { + code = codeMatch.Groups[5].Value; + deleteOrig = string.IsNullOrWhiteSpace(codeMatch.Groups[1].Value); + } + code = code.Trim(' ', '\t', '\r', '\n'); + code = emptyLines.Replace(code, "\n"); - code = "Reformatted " + toRefactor.Author.Mention + " code\n" + "```" + language + "\n" + code + "\n```"; + if (langEmoji == EmojiEnum.CSharp || langEmoji == EmojiEnum.Cpp || langEmoji == EmojiEnum.Java || langEmoji == EmojiEnum.Javascript) code = FixIndentation(code); - if (guessed == "no one" && language != null) { - langEmoji = GetLanguageEmoji(language); - } + code = "Reformatted " + toRefactor.Author.Mention + " code\n" + "```" + language + "\n" + code + "\n```"; - DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); - DiscordEmoji autoRefactored = UtilityFunctions.GetEmoji(EmojiEnum.AutoRefactored); - DiscordEmoji emoji = UtilityFunctions.GetEmoji(langEmoji); - try { - if (autoRefactored != null) { - await Task.Delay(120); - await replacement.CreateReactionAsync(autoRefactored); + if (guessed == "no one" && language != null) { + langEmoji = GetLanguageEmoji(language); } - if (emoji != null) { - await Task.Delay(120); - await replacement.CreateReactionAsync(emoji); - } - if (deleteOrig) { - await Task.Delay(120); - List toDelete = new List { toRefactor, ctx.Message }; - await ctx.Channel.DeleteMessagesAsync(toDelete); - } - else { - await Task.Delay(120); - await ctx.Message.DeleteAsync(); + + DiscordMessage replacement = await ctx.Channel.SendMessageAsync(code); + DiscordEmoji autoRefactored = Utils.GetEmoji(EmojiEnum.AutoRefactored); + DiscordEmoji emoji = Utils.GetEmoji(langEmoji); + try { + if (autoRefactored != null) { + await Task.Delay(120); + await replacement.CreateReactionAsync(autoRefactored); + } + if (emoji != null) { + await Task.Delay(120); + await replacement.CreateReactionAsync(emoji); + } + if (deleteOrig) { + await Task.Delay(120); + List toDelete = new List { toRefactor, ctx.Message }; + await ctx.Channel.DeleteMessagesAsync(toDelete); + } + else { + await Task.Delay(120); + await ctx.Message.DeleteAsync(); + } + } catch (Exception e) { + return ctx.RespondAsync("Exception: " + e.Message); } - } catch (Exception e) { - return ctx.RespondAsync("Exception: " + e.Message); + await Task.Delay(150); + return ctx.RespondAsync(""); + } catch (Exception ex) { + return ctx.RespondAsync(Utils.GenerateErrorAnswer("Refactor", ex)); } - await Task.Delay(150); - return ctx.RespondAsync(""); } readonly Regex lineOpenBlock = new Regex("^{(\\s*//.*|\\s*/\\*/.*)?$", RegexOptions.Multiline, TimeSpan.FromSeconds(1)); diff --git a/UPBot Code/Commands/Stats.cs b/UPBot Code/Commands/Stats.cs index 8fc41d0..3923e10 100644 --- a/UPBot Code/Commands/Stats.cs +++ b/UPBot Code/Commands/Stats.cs @@ -29,59 +29,57 @@ public class Stats : BaseCommandModule { [Command("stats")] - [Description("Provides server stats for the 4 most used channels (Unity, CSharp, Help 1, and Help 2")] + [Description("Provides server stats for specific channels, with no parameters checks the most 4 commons channels")] + [Cooldown(1, 60, CooldownBucketType.Channel | CooldownBucketType.User)] public async Task DoStats(CommandContext ctx) { await GenerateStats(ctx, null, 100); } [Command("stats")] - [Description("Provides server stats for a specific channel")] - public async Task DoStats(CommandContext ctx, DiscordChannel channel) { + [Description("Provides server stats for specific channels")] + [Cooldown(1, 60, CooldownBucketType.Channel | CooldownBucketType.User)] + public async Task DoStats(CommandContext ctx, [Description("Specific channel for the stats")] DiscordChannel channel) { await GenerateStats(ctx, channel, 100); } [Command("stats")] - [Description("Provides server stats, for a specified chanenl and with the required number of messages")] - public async Task DoStats(CommandContext ctx, DiscordChannel channel, int numMessages) { + [Description("Provides server stats for specific channels")] + [Cooldown(1, 60, CooldownBucketType.Channel | CooldownBucketType.User)] + public async Task DoStats(CommandContext ctx, [Description("Specific channel for the stats")] DiscordChannel channel, [Description("Number of messages to check")] int numMessages) { await GenerateStats(ctx, channel, numMessages); } [Command("stats")] - [Description("Provides server stats, for a specified chanenl and with the required number of messages")] - public async Task DoStats(CommandContext ctx, int numMessages, DiscordChannel channel) { - await GenerateStats(ctx, channel, numMessages); - } - [Command("stats")] - [Description("Provides server stats for the 4 most used channels, with the required number of messages")] - public async Task DoStats(CommandContext ctx, int numMessages) { + [Description("Provides server stats for specific channels")] + [Cooldown(1, 60, CooldownBucketType.Channel | CooldownBucketType.User)] + public async Task DoStats(CommandContext ctx, [Description("Number of messages to check")] int numMessages) { await GenerateStats(ctx, null, numMessages); } public async Task GenerateStats(CommandContext ctx, DiscordChannel channel, int numMessages) { - UtilityFunctions.LogUserCommand(ctx); - - DateTime start = DateTime.Now; - if (numMessages > 2000) numMessages = 2000; + Utils.LogUserCommand(ctx); + try { + DateTime start = DateTime.Now; + if (numMessages > 2000) numMessages = 2000; + + ulong[] channelIDs; + string[] channelNames; + if (channel == null) { + channelIDs = defChannelIDs; + channelNames = defChannelNames; + } + else { + channelIDs = new ulong[] { channel.Id }; + channelNames = new string[] { channel.Name }; + } - ulong[] channelIDs; - string[] channelNames; - if (channel == null) { - channelIDs = defChannelIDs; - channelNames = defChannelNames; - } - else { - channelIDs = new ulong[]{ channel.Id }; - channelNames = new string[] { channel.Name }; - } + DiscordGuild g = ctx.Guild; + string title = Utils.GetEmojiSnowflakeID(Utils.GetEmoji(EmojiEnum.UnitedProgramming)) + " United Programming Statistics"; + string description = " ---- Fetching data 0/" + channelIDs.Length + " ---- Channel " + channelNames[0] + " ---- "; - DiscordGuild g = ctx.Guild; - string title = UtilityFunctions.GetEmojiSnowflakeID(UtilityFunctions.GetEmoji(EmojiEnum.UnitedProgramming)) + " United Programming Statistics"; - string description = " ---- Fetching data 0/" + channelIDs.Length + " ---- Channel " + channelNames[0] + " ---- "; - - var e = UtilityFunctions.BuildEmbed(title, description, DiscordColor.Black); - int fieldPos = e.Fields.Count - 1; - DiscordMessage m = await UtilityFunctions.LogEmbed(e, ctx, true); + var e = Utils.BuildEmbed(title, description, DiscordColor.Black); + int fieldPos = e.Fields.Count - 1; + DiscordMessage m = await Utils.LogEmbed(e, ctx, true); - int step = 0; - try { + int step = 0; await Task.Delay(120); Dictionary mentioners = new Dictionary(); Dictionary mentioneds = new Dictionary(); @@ -164,25 +162,20 @@ public async Task GenerateStats(CommandContext ctx, DiscordChannel channel, int double time = (DateTime.Now - start).TotalMilliseconds / 1000; if (channelIDs.Length == 1) - e.WithFooter("Statistics from channel " + channelNames[0] + " and " + numMessages + " messages per channel.\nGenerated in " + time.ToString("N1") + " seconds"); + e.WithFooter("Statistics from channel " + channelNames[0] + " and " + numMessages + " messages per channel.\nGenerated in " + time.ToString("N1") + " seconds"); else e.WithFooter("Statistics from " + channelIDs.Length + " channels and " + numMessages + " messages per channel.\nGenerated in " + time.ToString("N1") + " seconds"); + await m.ModifyAsync(e.Build()); } catch (Exception ex) { - + await ctx.RespondAsync(Utils.GenerateErrorAnswer("Stats", ex)); } - await m.ModifyAsync(e.Build()); } public class Mentioner { public ulong member; public int num; - } - const ulong idUnityChannel = 830904407540367441ul; - const ulong idCSharpChannel = 830904726375628850ul; - const ulong idHelp1Channel = 830921265648631878ul; - const ulong idHelp2Channel = 830921315657449472ul; } diff --git a/UPBot Code/Commands/Version.cs b/UPBot Code/Commands/Version.cs new file mode 100644 index 0000000..69cc8d1 --- /dev/null +++ b/UPBot Code/Commands/Version.cs @@ -0,0 +1,27 @@ +ο»Ώusing DSharpPlus.CommandsNext; +using DSharpPlus.CommandsNext.Attributes; +using DSharpPlus.Entities; +using System; +using System.Threading.Tasks; +/// +/// This command implements a WhoIs command. +/// It gives info about a Discord User or yourself +/// author: CPU +/// +public class Version : BaseCommandModule { + + [Command("Version")] + [Description("Get version information about the bot.")] + public async Task VersionCommand(CommandContext ctx) { + DiscordMember cpu = ctx.Guild.GetMemberAsync(231753250687287296ul).Result; + DiscordMember duck = ctx.Guild.GetMemberAsync(411526180873961494ul).Result; + DiscordMember eremiell = ctx.Guild.GetMemberAsync(340661564556312591ul).Result; + DiscordMember slice = ctx.Guild.GetMemberAsync(486133356858310656ul).Result; + DiscordMember jonathan = ctx.Guild.GetMemberAsync(608994148313333763ul).Result; + + await ctx.Message.RespondAsync(Utils.BuildEmbed("United Programming Bot", + "**Version**: " + Utils.GetVersion() + "\n\nContributors: " + + cpu.Mention + ", " + duck.Mention + ", " + eremiell.Mention + ", " + slice.Mention + ", " + jonathan.Mention + + "\n\nCode available on https://github.com/United-Programming/UPBot/", Utils.Yellow).Build()); + } +} \ No newline at end of file diff --git a/UPBot Code/Commands/WhoIs.cs b/UPBot Code/Commands/WhoIs.cs index 4d14048..4e238e2 100644 --- a/UPBot Code/Commands/WhoIs.cs +++ b/UPBot Code/Commands/WhoIs.cs @@ -17,87 +17,91 @@ public async Task WhoIsCommand(CommandContext ctx) { // Basic version without pa await GenerateWhoIs(ctx, null); } + [Command("whois")] + public async Task WhoIsCommand(CommandContext ctx, [Description("The user to get info from.")] DiscordMember member) { // Standard version with a user + await GenerateWhoIs(ctx, member); + } + [Command("whoami")] [Description("Get information about your own Discord account.")] public async Task WhoAmICommand(CommandContext ctx) { // Alternate version without parameters await GenerateWhoIs(ctx, null); } - [Command("whois")] - public async Task WhoIsCommand(CommandContext ctx, DiscordMember member) { // Standard version with a user - await GenerateWhoIs(ctx, member); - } - private Task GenerateWhoIs(CommandContext ctx, DiscordMember m) { - UtilityFunctions.LogUserCommand(ctx); - if (m == null) { // If we do not have a user we use the member that invoked the command - m = ctx.Member; - } - bool you = m == ctx.Member; - - DateTimeOffset jdate = m.JoinedAt.UtcDateTime; - string joined = jdate.Year + "/" + jdate.Month + "/" + jdate.Day; - DateTimeOffset cdate = m.CreationTimestamp.UtcDateTime; - string creation = cdate.Year + "/" + cdate.Month + "/" + cdate.Day; + Utils.LogUserCommand(ctx); + try { + if (m == null) { // If we do not have a user we use the member that invoked the command + m = ctx.Member; + } + bool you = m == ctx.Member; - int daysJ = (int)(DateTime.Now - m.JoinedAt.DateTime).TotalDays; - int daysA = (int)(DateTime.Now - m.CreationTimestamp.DateTime).TotalDays; - double years = daysA / 365.25; + DateTimeOffset jdate = m.JoinedAt.UtcDateTime; + string joined = jdate.Year + "/" + jdate.Month + "/" + jdate.Day; + DateTimeOffset cdate = m.CreationTimestamp.UtcDateTime; + string creation = cdate.Year + "/" + cdate.Month + "/" + cdate.Day; - string title = "Who is the user " + m.DisplayName + "#" + m.Discriminator; - string description = m.Username + " joined on " + joined + " (" + daysJ + " days)\n Account created on " + - creation + " (" + daysA + " days, " + years.ToString("N1") + " years)"; - var embed = UtilityFunctions.BuildEmbed(title, description, m.Color); - embed.WithThumbnail(m.AvatarUrl, 64, 64); + int daysJ = (int)(DateTime.Now - m.JoinedAt.DateTime).TotalDays; + int daysA = (int)(DateTime.Now - m.CreationTimestamp.DateTime).TotalDays; + double years = daysA / 365.25; - embed.AddField("Is you", you ? "βœ“" : "❌", true); - embed.AddField("Is a bot", m.IsBot ? "πŸ€–" : "❌", true); - embed.AddField("Is the boss", m.IsOwner ? "πŸ‘‘" : "❌", true); - embed.AddField("Is Muted", m.IsMuted ? "βœ“" : "❌", true); - embed.AddField("Is Deafened", m.IsDeafened ? "βœ“" : "❌", true); + string title = "Who is the user " + m.DisplayName + "#" + m.Discriminator; + string description = m.Username + " joined on " + joined + " (" + daysJ + " days)\n Account created on " + + creation + " (" + daysA + " days, " + years.ToString("N1") + " years)"; + var embed = Utils.BuildEmbed(title, description, m.Color); + embed.WithThumbnail(m.AvatarUrl, 64, 64); - if (m.Locale != null) embed.AddField("Speaks", m.Locale, true); - if (m.Nickname != null) embed.AddField("Is called", m.Nickname, true); - embed.AddField("Avatar Hex Color", m.Color.ToString(), true); + embed.AddField("Is you", you ? "βœ“" : "❌", true); + embed.AddField("Is a bot", m.IsBot ? "πŸ€–" : "❌", true); + embed.AddField("Is the boss", m.IsOwner ? "πŸ‘‘" : "❌", true); + embed.AddField("Is Muted", m.IsMuted ? "βœ“" : "❌", true); + embed.AddField("Is Deafened", m.IsDeafened ? "βœ“" : "❌", true); - if (m.PremiumSince != null) { - DateTimeOffset bdate = ((DateTimeOffset)m.PremiumSince).UtcDateTime; - string booster = bdate.Year + "/" + bdate.Month + "/" + bdate.Day; - embed.AddField("Booster", "From " + booster, true); - } - if (m.Flags != null) embed.AddField("Flags", m.Flags.ToString(), true); // Only the default flags will be shown. This bot will not be very diffused so probably we do not need specific checks for flags + if (m.Locale != null) embed.AddField("Speaks", m.Locale, true); + if (m.Nickname != null) embed.AddField("Is called", m.Nickname, true); + embed.AddField("Avatar Hex Color", m.Color.ToString(), true); - string roles = ""; - int num = 0; - foreach (DiscordRole role in m.Roles) { - roles += role.Mention + " "; - num++; - } - if (num == 1) - embed.AddField("Role", roles, false); - else - embed.AddField(num + " Roles", roles, false); + if (m.PremiumSince != null) { + DateTimeOffset bdate = ((DateTimeOffset)m.PremiumSince).UtcDateTime; + string booster = bdate.Year + "/" + bdate.Month + "/" + bdate.Day; + embed.AddField("Booster", "From " + booster, true); + } + if (m.Flags != null) embed.AddField("Flags", m.Flags.ToString(), true); // Only the default flags will be shown. This bot will not be very diffused so probably we do not need specific checks for flags + + string roles = ""; + int num = 0; + foreach (DiscordRole role in m.Roles) { + roles += role.Mention + " "; + num++; + } + if (num == 1) + embed.AddField("Role", roles, false); + else + embed.AddField(num + " Roles", roles, false); - string perms = ""; // Not all permissions are shown - if (m.Permissions.HasFlag(DSharpPlus.Permissions.CreateInstantInvite)) perms += ", Invite"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.KickMembers)) perms += ", Kick"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.BanMembers)) perms += ", Ban"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.Administrator)) perms += ", Admin"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageChannels)) perms += ", Manage Channels"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageGuild)) perms += ", Manage Server"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.AddReactions)) perms += ", Reactions"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ViewAuditLog)) perms += ", Audit"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageMessages)) perms += ", Manage Messages"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.EmbedLinks)) perms += ", Links"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.AttachFiles)) perms += ", Files"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.UseExternalEmojis)) perms += ", Ext Emojis"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.Speak)) perms += ", Speak"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageRoles)) perms += ", Manage Roles"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageEmojis)) perms += ", Manage Emojis"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.UseSlashCommands)) perms += ", Use Bot"; - if (m.Permissions.HasFlag(DSharpPlus.Permissions.UsePublicThreads)) perms += ", Use Threads"; - if (perms.Length > 0) embed.AddField("Permissions", perms.Substring(2), false); + string perms = ""; // Not all permissions are shown + if (m.Permissions.HasFlag(DSharpPlus.Permissions.CreateInstantInvite)) perms += ", Invite"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.KickMembers)) perms += ", Kick"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.BanMembers)) perms += ", Ban"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.Administrator)) perms += ", Admin"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageChannels)) perms += ", Manage Channels"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageGuild)) perms += ", Manage Server"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.AddReactions)) perms += ", Reactions"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ViewAuditLog)) perms += ", Audit"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageMessages)) perms += ", Manage Messages"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.EmbedLinks)) perms += ", Links"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.AttachFiles)) perms += ", Files"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.UseExternalEmojis)) perms += ", Ext Emojis"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.Speak)) perms += ", Speak"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageRoles)) perms += ", Manage Roles"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.ManageEmojis)) perms += ", Manage Emojis"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.UseSlashCommands)) perms += ", Use Bot"; + if (m.Permissions.HasFlag(DSharpPlus.Permissions.UsePublicThreads)) perms += ", Use Threads"; + if (perms.Length > 0) embed.AddField("Permissions", perms.Substring(2), false); - return ctx.RespondAsync(embed.Build()); + return ctx.RespondAsync(embed.Build()); + } catch (Exception ex) { + return ctx.RespondAsync(Utils.GenerateErrorAnswer("WhoIs", ex)); + } } } \ No newline at end of file diff --git a/UPBot Code/Program.cs b/UPBot Code/Program.cs index 2b20291..1544434 100644 --- a/UPBot Code/Program.cs +++ b/UPBot Code/Program.cs @@ -23,8 +23,8 @@ static async Task MainAsync(string token, string prefix) { }); CustomCommandsService.DiscordClient = discord; - UtilityFunctions.InitClient(discord); - var commands = discord.UseCommandsNext(new CommandsNextConfiguration() { + Utils.InitClient(discord); + CommandsNextExtension commands = discord.UseCommandsNext(new CommandsNextConfiguration() { StringPrefixes = new[] { prefix[0].ToString() } // The backslash will be the default command prefix if not specified in the parameters }); commands.CommandErrored += CustomCommandsService.CommandError; @@ -36,7 +36,7 @@ static async Task MainAsync(string token, string prefix) { await CustomCommandsService.LoadCustomCommands(); await discord.ConnectAsync(); // Connects and wait forever - UtilityFunctions.Log("Logging [re]Started at: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:dd")); + Utils.Log("Logging [re]Started at: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:dd") + " --------------------------------"); AppreciationTracking.Init(); discord.GuildMemberAdded += MembersTracking.DiscordMemberAdded; diff --git a/UPBot Code/UtilityFunctions.cs b/UPBot Code/Utils.cs similarity index 81% rename from UPBot Code/UtilityFunctions.cs rename to UPBot Code/Utils.cs index 9727cc8..5145f56 100644 --- a/UPBot Code/UtilityFunctions.cs +++ b/UPBot Code/Utils.cs @@ -2,6 +2,7 @@ using DSharpPlus.CommandsNext; using DSharpPlus.Entities; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading.Tasks; @@ -10,7 +11,7 @@ /// Utility functions that don't belong to a specific class or a specific command /// "General-purpose" function, which can be needed anywhere. /// -public static class UtilityFunctions +public static class Utils { /// /// Common colors @@ -27,15 +28,23 @@ public static class UtilityFunctions private static DiscordMember mySelf; private static DiscordGuild guild; - public static void SetMyself(DiscordClient c) { - + public static string GetVersion() { + return "0.1 beta - 2021/08/19"; } + /// + /// Returns the Bot user as Member of the United Programming Guild + /// + /// public static DiscordMember GetMyself() { if (mySelf==null) mySelf = client.Guilds[830900174553481236ul].CurrentMember; return mySelf; } + /// + /// Gets the UNitedProgramming Guild + /// + /// public static DiscordGuild GetGuild() { if (guild != null) return guild; while (client == null) Task.Delay(1000); @@ -132,6 +141,21 @@ public static async Task BuildEmbedAndExecute(string title, stri return await LogEmbed(embedBuilder, ctx, respond); } + /// + /// Quick shortcut to generate an error message + /// + /// The error to display + /// + internal static DiscordEmbed GenerateErrorAnswer(string cmd, Exception exception) { + DiscordEmbedBuilder e = new DiscordEmbedBuilder { + Color = Red, + Title = "Error in " + cmd, + Description = exception.Message + }; + Log("Error in " + cmd + ": " + exception.Message); + return e.Build(); + } + /// /// Logs an embed as a message in the relevant channel /// @@ -208,7 +232,7 @@ internal static void LogUserCommand(CommandContext ctx) { /// /// internal static void Log(string msg) { - Console.WriteLine(DateTime.Now.ToString(sortableDateTimeFormat.SortableDateTimePattern) + "=> " + msg); + Console.WriteLine(msg); try { logs.WriteLine(msg); logs.FlushAsync(); @@ -255,8 +279,50 @@ internal static async Task ErrorCallback(CommandErrors error, CommandContext ctx break; } - await UtilityFunctions.BuildEmbedAndExecute("Error", message, red, ctx, respond); + await Utils.BuildEmbedAndExecute("Error", message, red, ctx, respond); + } + + /// + /// Used to delete some messages after a while + /// + /// + public static Task DeleteDelayed(int seconds, DiscordMessage msg1) { + Task.Run(() => DelayAfterAWhile(msg1, seconds * 1000)); + return Task.FromResult(0); + } + + /// + /// Used to delete some messages after a while + /// + /// + /// + public static Task DeleteDelayed(int seconds, DiscordMessage msg1, DiscordMessage msg2) { + Task.Run(() => DelayAfterAWhile(msg1, seconds * 1000)); + Task.Run(() => DelayAfterAWhile(msg2, seconds * 1000)); + return Task.FromResult(0); } + + /// + /// Used to delete some messages after a while + /// + /// + /// + /// + public static Task DeleteDelayed(int seconds, DiscordMessage msg1, DiscordMessage msg2, DiscordMessage msg3) { + Task.Run(() => DelayAfterAWhile(msg1, seconds * 1000)); + Task.Run(() => DelayAfterAWhile(msg2, seconds * 1000)); + Task.Run(() => DelayAfterAWhile(msg3, seconds * 1000)); + return Task.FromResult(0); + } + + static void DelayAfterAWhile(DiscordMessage msg, int delay) { + try { + Task.Delay(delay).Wait(); + msg.DeleteAsync().Wait(); + } catch (Exception) { } + } + + } public enum EmojiEnum {