public static async Task <IReadOnlyDictionary <ulong, List <EmojiReaction> > > GetEmojiReactionsForAllGuildsAsync(this DBService db) { var ereactions = new Dictionary <ulong, List <EmojiReaction> >(); await db.ExecuteCommandAsync(async (cmd) => { cmd.CommandText = "SELECT id, gid, trigger, reaction FROM gf.emoji_reactions;"; using (var reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false)) { while (await reader.ReadAsync().ConfigureAwait(false)) { ulong gid = (ulong)(long)reader["gid"]; if (ereactions.ContainsKey(gid)) { if (ereactions[gid] == null) { ereactions[gid] = new List <EmojiReaction>(); } } else { ereactions.Add(gid, new List <EmojiReaction>()); } int id = (int)reader["id"]; string trigger = (string)reader["trigger"]; string emoji = (string)reader["reaction"]; EmojiReaction conflict = ereactions[gid].FirstOrDefault(tr => tr.Response == emoji); if (conflict != null) { conflict.AddTrigger(trigger, isRegex: true); } else { ereactions[gid].Add(new EmojiReaction(id, trigger, emoji, isRegex: true)); } } } }); return(new ReadOnlyDictionary <ulong, List <EmojiReaction> >(ereactions)); }
private async Task AddEmojiReactionAsync(CommandContext ctx, DiscordEmoji emoji, bool regex, params string[] triggers) { if (triggers == null) { throw new InvalidCommandUsageException("Missing trigger words!"); } var eb = new StringBuilder(); foreach (string trigger in triggers.Select(t => t.ToLowerInvariant())) { if (trigger.Length > 120) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} is too long (120 chars max)."); continue; } if (!this.Shared.EmojiReactions.ContainsKey(ctx.Guild.Id)) { if (!this.Shared.EmojiReactions.TryAdd(ctx.Guild.Id, new ConcurrentHashSet <EmojiReaction>())) { throw new ConcurrentOperationException("Failed to create emoji reaction data structure"); } } if (regex && !trigger.IsValidRegex()) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} is not a valid regular expression."); continue; } string ename = emoji.GetDiscordName(); if (this.Shared.EmojiReactions[ctx.Guild.Id].Where(er => er.ContainsTriggerPattern(trigger)).Any(er => er.Response == ename)) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} already exists for this emoji."); continue; } int id = 0; try { id = await this.Database.AddEmojiReactionAsync(ctx.Guild.Id, trigger, ename, regex : regex); } catch (Exception e) { this.Shared.LogProvider.LogException(LogLevel.Warning, e); eb.AppendLine($"Warning: Failed to add trigger {Formatter.Bold(trigger)} to the database."); } EmojiReaction reaction = this.Shared.EmojiReactions[ctx.Guild.Id].FirstOrDefault(tr => tr.Response == ename); if (reaction != null) { if (!reaction.AddTrigger(trigger, isRegex: regex)) { throw new CommandFailedException($"Failed to add trigger {Formatter.Bold(trigger)}."); } } else { if (!this.Shared.EmojiReactions[ctx.Guild.Id].Add(new EmojiReaction(id, trigger, ename, isRegex: regex))) { throw new CommandFailedException($"Failed to add trigger {Formatter.Bold(trigger)}."); } } } DiscordChannel logchn = this.Shared.GetLogChannelForGuild((DiscordClientImpl)ctx.Client, ctx.Guild); if (logchn != null) { var emb = new DiscordEmbedBuilder() { Title = "New emoji reactions added", Color = this.ModuleColor }; emb.AddField("User responsible", ctx.User.Mention, inline: true); emb.AddField("Invoked in", ctx.Channel.Mention, inline: true); emb.AddField("Reaction", emoji, inline: true); emb.AddField("Triggers", string.Join("\n", triggers)); if (eb.Length > 0) { emb.AddField("With errors", eb.ToString()); } await logchn.SendMessageAsync(embed : emb.Build()); } if (eb.Length > 0) { await this.InformFailureAsync(ctx, $"Action finished with following warnings/errors:\n\n{eb.ToString()}"); } else { await this.InformAsync(ctx, "Successfully added all given emoji reactions.", important : false); } }
private async Task AddEmojiReactionAsync(CommandContext ctx, DiscordEmoji emoji, bool regex, params string[] triggers) { if (emoji is DiscordGuildEmoji && !ctx.Guild.Emojis.Values.Contains(emoji)) { throw new CommandFailedException("The reaction has to be an emoji from this guild."); } if (triggers is null || !triggers.Any()) { throw new InvalidCommandUsageException("Missing trigger words!"); } if (!this.Shared.EmojiReactions.ContainsKey(ctx.Guild.Id)) { if (!this.Shared.EmojiReactions.TryAdd(ctx.Guild.Id, new ConcurrentHashSet <EmojiReaction>())) { throw new ConcurrentOperationException("Failed to create emoji reaction data structure"); } } int id; using (DatabaseContext db = this.Database.CreateContext()) { DatabaseEmojiReaction dber = db.EmojiReactions.FirstOrDefault(er => er.GuildId == ctx.Guild.Id && er.Reaction == emoji.GetDiscordName()); if (dber is null) { dber = new DatabaseEmojiReaction { GuildId = ctx.Guild.Id, Reaction = emoji.GetDiscordName() }; db.EmojiReactions.Add(dber); await db.SaveChangesAsync(); } foreach (string trigger in triggers) { dber.DbTriggers.Add(new DatabaseEmojiReactionTrigger { ReactionId = dber.Id, Trigger = regex ? trigger : Regex.Escape(trigger) }); } await db.SaveChangesAsync(); id = dber.Id; } var eb = new StringBuilder(); foreach (string trigger in triggers.Select(t => t.ToLowerInvariant())) { if (trigger.Length > 120) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} is too long (120 chars max)."); continue; } if (regex && !trigger.IsValidRegex()) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} is not a valid regular expression."); continue; } ConcurrentHashSet <EmojiReaction> ereactions = this.Shared.EmojiReactions[ctx.Guild.Id]; string ename = emoji.GetDiscordName(); if (ereactions.Where(er => er.ContainsTriggerPattern(trigger)).Any(er => er.Response == ename)) { eb.AppendLine($"Error: Trigger {Formatter.Bold(trigger)} already exists for this emoji."); continue; } EmojiReaction reaction = ereactions.FirstOrDefault(tr => tr.Response == ename); if (reaction is null) { if (!ereactions.Add(new EmojiReaction(id, trigger, ename, isRegex: regex))) { throw new CommandFailedException($"Failed to add trigger {Formatter.Bold(trigger)}."); } } else { if (!reaction.AddTrigger(trigger, isRegex: regex)) { throw new CommandFailedException($"Failed to add trigger {Formatter.Bold(trigger)}."); } } } DiscordChannel logchn = this.Shared.GetLogChannelForGuild(ctx.Client, ctx.Guild); if (!(logchn is null)) { var emb = new DiscordEmbedBuilder { Title = "New emoji reactions added", Color = this.ModuleColor }; emb.AddField("User responsible", ctx.User.Mention, inline: true); emb.AddField("Invoked in", ctx.Channel.Mention, inline: true); emb.AddField("Reaction", emoji, inline: true); emb.AddField("Triggers", string.Join("\n", triggers)); if (eb.Length > 0) { emb.AddField("With errors", eb.ToString()); } await logchn.SendMessageAsync(embed : emb.Build()); } if (eb.Length > 0) { await this.InformFailureAsync(ctx, $"Action finished with following warnings/errors:\n\n{eb.ToString()}"); } else { await this.InformAsync(ctx, "Successfully added all given emoji reactions.", important : false); } }