From 07aa25c56f7dc3f7a9971806e9775fffb213518e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Mar 2017 08:08:13 +0100 Subject: [PATCH] You can now use permissions module to disable individual custom reactions. Not fully tested, seems to work. public bot global cooldown reduced to 750ms, slot cooldown from 2 to 1 second --- .../CustomReactions/CustomReactions.cs | 70 +++++++------------ .../Modules/Gambling/Commands/Slots.cs | 2 +- .../Modules/Permissions/Permissions.cs | 34 ++++----- src/NadekoBot/NadekoBot.cs | 1 + src/NadekoBot/Services/CommandHandler.cs | 47 +++++++++++-- .../Database/Models/CustomReaction.cs | 2 + .../Impl/GuildConfigRepository.cs | 5 +- .../TypeReaders/BotCommandTypeReader.cs | 44 ++++++++++++ 8 files changed, 136 insertions(+), 69 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index efd3717e..bbe73e51 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -13,9 +13,27 @@ using Discord.WebSocket; using System; using Newtonsoft.Json; using NadekoBot.DataStructures; +using NLog.Fluent; namespace NadekoBot.Modules.CustomReactions { + public static class CustomReactionExtensions + { + public static Task Send(this CustomReaction cr, IUserMessage context) + { + var channel = context.Channel; + + CustomReactions.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old); + + CREmbed crembed; + if (CREmbed.TryParse(cr.Response, out crembed)) + { + return channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); + } + return channel.SendMessageAsync(cr.ResponseWithContext(context)); + } + } + [NadekoModule("CustomReactions", ".")] public class CustomReactions : NadekoTopLevelModule { @@ -25,7 +43,7 @@ namespace NadekoBot.Modules.CustomReactions public static ConcurrentDictionary ReactionStats { get; } = new ConcurrentDictionary(); - private static new readonly Logger _log; + private new static readonly Logger _log; static CustomReactions() { @@ -43,11 +61,11 @@ namespace NadekoBot.Modules.CustomReactions public void ClearStats() => ReactionStats.Clear(); - public static async Task TryExecuteCustomReaction(SocketUserMessage umsg) + public static async Task TryGetCustomReaction(SocketUserMessage umsg) { var channel = umsg.Channel as SocketTextChannel; if (channel == null) - return false; + return null; var content = umsg.Content.Trim().ToLowerInvariant(); CustomReaction[] reactions; @@ -70,26 +88,9 @@ namespace NadekoBot.Modules.CustomReactions var reaction = rs[new NadekoRandom().Next(0, rs.Length)]; if (reaction != null) { - if (reaction.Response != "-") - { - CREmbed crembed; - if (CREmbed.TryParse(reaction.Response, out crembed)) - { - try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - } - else - { - try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - } - } - - ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); - return true; + if (reaction.Response == "-") + return null; + return reaction; } } } @@ -103,29 +104,10 @@ namespace NadekoBot.Modules.CustomReactions return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); }).ToArray(); if (grs.Length == 0) - return false; + return null; var greaction = grs[new NadekoRandom().Next(0, grs.Length)]; - if (greaction != null) - { - CREmbed crembed; - if (CREmbed.TryParse(greaction.Response, out crembed)) - { - try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - } - else - { - try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - } - ReactionStats.AddOrUpdate(greaction.Trigger, 1, (k, old) => ++old); - return true; - } - return false; + return greaction; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index ea20b4b1..79dbe75a 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -223,7 +223,7 @@ namespace NadekoBot.Modules.Gambling { var _ = Task.Run(async () => { - await Task.Delay(2000); + await Task.Delay(1500); _runningUsers.Remove(Context.User.Id); }); } diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index bc95d158..837bea9d 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -12,6 +12,7 @@ using Discord.WebSocket; using System.Diagnostics; using Microsoft.EntityFrameworkCore; using NadekoBot.DataStructures; +using NadekoBot.TypeReaders; using NLog; namespace NadekoBot.Modules.Permissions @@ -89,6 +90,7 @@ namespace NadekoBot.Modules.Permissions var gc = uow.GuildConfigs.For(oc.Key, set => set.Include(x => x.Permissions)); var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList(); + uow._context.Set().RemoveRange(oldPerms); gc.RootPermission = null; if (oldPerms.Count > 2) { @@ -316,27 +318,27 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task SrvrCmd(CommandInfo command, PermissionAction action) + public async Task SrvrCmd(CommandOrCrInfo command, PermissionAction action) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.Server, PrimaryTargetId = 0, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("sx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command")).ConfigureAwait(false); } else { await ReplyConfirmLocalized("sx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command")).ConfigureAwait(false); } } @@ -370,28 +372,28 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task UsrCmd(CommandInfo command, PermissionAction action, [Remainder] IGuildUser user) + public async Task UsrCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IGuildUser user) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.User, PrimaryTargetId = user.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("ux_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(user.ToString())).ConfigureAwait(false); } else { await ReplyConfirmLocalized("ux_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(user.ToString())).ConfigureAwait(false); } @@ -428,7 +430,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task RoleCmd(CommandInfo command, PermissionAction action, [Remainder] IRole role) + public async Task RoleCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IRole role) { if (role == role.Guild.EveryoneRole) return; @@ -438,21 +440,21 @@ namespace NadekoBot.Modules.Permissions PrimaryTarget = PrimaryPermissionType.Role, PrimaryTargetId = role.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("rx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(role.Name)).ConfigureAwait(false); } else { await ReplyConfirmLocalized("rx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(role.Name)).ConfigureAwait(false); } @@ -493,28 +495,28 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl) + public async Task ChnlCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] ITextChannel chnl) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.Channel, PrimaryTargetId = chnl.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("cx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(chnl.Name)).ConfigureAwait(false); } else { await ReplyConfirmLocalized("cx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(chnl.Name)).ConfigureAwait(false); } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 7da895d6..6673cacb 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -110,6 +110,7 @@ namespace NadekoBot //setup typereaders CommandService.AddTypeReader(new PermissionActionTypeReader()); CommandService.AddTypeReader(new CommandTypeReader()); + CommandService.AddTypeReader(new CommandOrCrTypeReader()); CommandService.AddTypeReader(new ModuleTypeReader()); CommandService.AddTypeReader(new GuildTypeReader()); diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index d6678d23..ae005e95 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -29,11 +29,7 @@ namespace NadekoBot.Services } public class CommandHandler { -#if GLOBAL_NADEKO - public const int GlobalCommandsCooldown = 1500; -#else public const int GlobalCommandsCooldown = 750; -#endif private readonly DiscordShardedClient _client; private readonly CommandService _commandService; @@ -274,9 +270,47 @@ namespace NadekoBot.Services // maybe this message is a custom reaction // todo log custom reaction executions. return struct with info - var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); - if (crExecuted) //if it was, don't execute the command + var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); + if (cr != null) //if it was, don't execute the command + { + try + { + if (guild != null) + { + PermissionCache pc; + if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(guild.Id, + set => set.Include(x => x.Permissions)); + Permissions.UpdateCache(config); + } + Permissions.Cache.TryGetValue(guild.Id, out pc); + if (pc == null) + throw new Exception("Cache is null."); + } + int index; + if ( + !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", + out index)) + { + //todo print in guild actually + var returnMsg = + $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; + _log.Info(returnMsg); + return; + } + } + await cr.Send(usrMsg).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } return; + } var exec3 = Environment.TickCount - execTime; @@ -384,6 +418,7 @@ namespace NadekoBot.Services PermissionCache pc; if (context.Guild != null) { + //todo move to permissions module? if (!Permissions.Cache.TryGetValue(context.Guild.Id, out pc)) { using (var uow = DbHandler.UnitOfWork()) diff --git a/src/NadekoBot/Services/Database/Models/CustomReaction.cs b/src/NadekoBot/Services/Database/Models/CustomReaction.cs index 394e5084..695c1cd3 100644 --- a/src/NadekoBot/Services/Database/Models/CustomReaction.cs +++ b/src/NadekoBot/Services/Database/Models/CustomReaction.cs @@ -12,6 +12,8 @@ namespace NadekoBot.Services.Database.Models public string Trigger { get; set; } public bool IsRegex { get; set; } public bool OwnerOnly { get; set; } + + public bool IsGlobal => !GuildId.HasValue; } public class ReactionResponse : DbEntity diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 428171b5..909a15d5 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -32,8 +32,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl /// /// Gets and creates if it doesn't exist a config for a guild. /// - /// - /// + /// For which guild + /// Use to manipulate the set however you want + /// Config for the guild public GuildConfig For(ulong guildId, Func, IQueryable> includes = null) { GuildConfig config; diff --git a/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs b/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs index 9b4e06c2..0699ae43 100644 --- a/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs +++ b/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs @@ -1,6 +1,8 @@ using Discord.Commands; using System.Linq; using System.Threading.Tasks; +using NadekoBot.Modules.CustomReactions; +using NadekoBot.Services.Database.Models; namespace NadekoBot.TypeReaders { @@ -17,4 +19,46 @@ namespace NadekoBot.TypeReaders return Task.FromResult(TypeReaderResult.FromSuccess(cmd)); } } + + public class CommandOrCrTypeReader : CommandTypeReader + { + public override async Task Read(ICommandContext context, string input) + { + input = input.ToUpperInvariant(); + + if (CustomReactions.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input)) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input)); + } + var guild = context.Guild; + if (guild != null) + { + CustomReaction[] crs; + if (CustomReactions.GuildReactions.TryGetValue(guild.Id, out crs)) + { + if (crs.Any(x => x.Trigger.ToUpperInvariant() == input)) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input)); + } + } + } + + var cmd = await base.Read(context, input); + if (cmd.IsSuccess) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First())); + } + return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found."); + } + } + + public class CommandOrCrInfo + { + public string Name { get; set; } + + public CommandOrCrInfo(string input) + { + this.Name = input; + } + } }