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

This commit is contained in:
Kwoth 2017-03-14 08:08:13 +01:00
parent 088008c23b
commit 07aa25c56f
8 changed files with 136 additions and 69 deletions

View File

@ -13,9 +13,27 @@ using Discord.WebSocket;
using System; using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using NadekoBot.DataStructures; using NadekoBot.DataStructures;
using NLog.Fluent;
namespace NadekoBot.Modules.CustomReactions namespace NadekoBot.Modules.CustomReactions
{ {
public static class CustomReactionExtensions
{
public static Task<IUserMessage> 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", ".")] [NadekoModule("CustomReactions", ".")]
public class CustomReactions : NadekoTopLevelModule public class CustomReactions : NadekoTopLevelModule
{ {
@ -25,7 +43,7 @@ namespace NadekoBot.Modules.CustomReactions
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>(); public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
private static new readonly Logger _log; private new static readonly Logger _log;
static CustomReactions() static CustomReactions()
{ {
@ -43,11 +61,11 @@ namespace NadekoBot.Modules.CustomReactions
public void ClearStats() => ReactionStats.Clear(); public void ClearStats() => ReactionStats.Clear();
public static async Task<bool> TryExecuteCustomReaction(SocketUserMessage umsg) public static async Task<CustomReaction> TryGetCustomReaction(SocketUserMessage umsg)
{ {
var channel = umsg.Channel as SocketTextChannel; var channel = umsg.Channel as SocketTextChannel;
if (channel == null) if (channel == null)
return false; return null;
var content = umsg.Content.Trim().ToLowerInvariant(); var content = umsg.Content.Trim().ToLowerInvariant();
CustomReaction[] reactions; CustomReaction[] reactions;
@ -70,26 +88,9 @@ namespace NadekoBot.Modules.CustomReactions
var reaction = rs[new NadekoRandom().Next(0, rs.Length)]; var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
if (reaction != null) if (reaction != null)
{ {
if (reaction.Response != "-") if (reaction.Response == "-")
{ return null;
CREmbed crembed; return reaction;
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;
} }
} }
} }
@ -103,29 +104,10 @@ namespace NadekoBot.Modules.CustomReactions
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
}).ToArray(); }).ToArray();
if (grs.Length == 0) if (grs.Length == 0)
return false; return null;
var greaction = grs[new NadekoRandom().Next(0, grs.Length)]; var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
if (greaction != null) return greaction;
{
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;
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]

View File

@ -223,7 +223,7 @@ namespace NadekoBot.Modules.Gambling
{ {
var _ = Task.Run(async () => var _ = Task.Run(async () =>
{ {
await Task.Delay(2000); await Task.Delay(1500);
_runningUsers.Remove(Context.User.Id); _runningUsers.Remove(Context.User.Id);
}); });
} }

View File

@ -12,6 +12,7 @@ using Discord.WebSocket;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NadekoBot.DataStructures; using NadekoBot.DataStructures;
using NadekoBot.TypeReaders;
using NLog; using NLog;
namespace NadekoBot.Modules.Permissions 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 gc = uow.GuildConfigs.For(oc.Key, set => set.Include(x => x.Permissions));
var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList(); var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList();
uow._context.Set<Permission>().RemoveRange(oldPerms);
gc.RootPermission = null; gc.RootPermission = null;
if (oldPerms.Count > 2) if (oldPerms.Count > 2)
{ {
@ -316,27 +318,27 @@ namespace NadekoBot.Modules.Permissions
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [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 await AddPermissions(Context.Guild.Id, new Permissionv2
{ {
PrimaryTarget = PrimaryPermissionType.Server, PrimaryTarget = PrimaryPermissionType.Server,
PrimaryTargetId = 0, PrimaryTargetId = 0,
SecondaryTarget = SecondaryPermissionType.Command, SecondaryTarget = SecondaryPermissionType.Command,
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), SecondaryTargetName = command.Name.ToLowerInvariant(),
State = action.Value, State = action.Value,
}); });
if (action.Value) if (action.Value)
{ {
await ReplyConfirmLocalized("sx_enable", await ReplyConfirmLocalized("sx_enable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command")).ConfigureAwait(false); GetText("of_command")).ConfigureAwait(false);
} }
else else
{ {
await ReplyConfirmLocalized("sx_disable", await ReplyConfirmLocalized("sx_disable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command")).ConfigureAwait(false); GetText("of_command")).ConfigureAwait(false);
} }
} }
@ -370,28 +372,28 @@ namespace NadekoBot.Modules.Permissions
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [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 await AddPermissions(Context.Guild.Id, new Permissionv2
{ {
PrimaryTarget = PrimaryPermissionType.User, PrimaryTarget = PrimaryPermissionType.User,
PrimaryTargetId = user.Id, PrimaryTargetId = user.Id,
SecondaryTarget = SecondaryPermissionType.Command, SecondaryTarget = SecondaryPermissionType.Command,
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), SecondaryTargetName = command.Name.ToLowerInvariant(),
State = action.Value, State = action.Value,
}); });
if (action.Value) if (action.Value)
{ {
await ReplyConfirmLocalized("ux_enable", await ReplyConfirmLocalized("ux_enable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(user.ToString())).ConfigureAwait(false); Format.Code(user.ToString())).ConfigureAwait(false);
} }
else else
{ {
await ReplyConfirmLocalized("ux_disable", await ReplyConfirmLocalized("ux_disable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(user.ToString())).ConfigureAwait(false); Format.Code(user.ToString())).ConfigureAwait(false);
} }
@ -428,7 +430,7 @@ namespace NadekoBot.Modules.Permissions
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [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) if (role == role.Guild.EveryoneRole)
return; return;
@ -438,21 +440,21 @@ namespace NadekoBot.Modules.Permissions
PrimaryTarget = PrimaryPermissionType.Role, PrimaryTarget = PrimaryPermissionType.Role,
PrimaryTargetId = role.Id, PrimaryTargetId = role.Id,
SecondaryTarget = SecondaryPermissionType.Command, SecondaryTarget = SecondaryPermissionType.Command,
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), SecondaryTargetName = command.Name.ToLowerInvariant(),
State = action.Value, State = action.Value,
}); });
if (action.Value) if (action.Value)
{ {
await ReplyConfirmLocalized("rx_enable", await ReplyConfirmLocalized("rx_enable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(role.Name)).ConfigureAwait(false); Format.Code(role.Name)).ConfigureAwait(false);
} }
else else
{ {
await ReplyConfirmLocalized("rx_disable", await ReplyConfirmLocalized("rx_disable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(role.Name)).ConfigureAwait(false); Format.Code(role.Name)).ConfigureAwait(false);
} }
@ -493,28 +495,28 @@ namespace NadekoBot.Modules.Permissions
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)] [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 await AddPermissions(Context.Guild.Id, new Permissionv2
{ {
PrimaryTarget = PrimaryPermissionType.Channel, PrimaryTarget = PrimaryPermissionType.Channel,
PrimaryTargetId = chnl.Id, PrimaryTargetId = chnl.Id,
SecondaryTarget = SecondaryPermissionType.Command, SecondaryTarget = SecondaryPermissionType.Command,
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), SecondaryTargetName = command.Name.ToLowerInvariant(),
State = action.Value, State = action.Value,
}); });
if (action.Value) if (action.Value)
{ {
await ReplyConfirmLocalized("cx_enable", await ReplyConfirmLocalized("cx_enable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(chnl.Name)).ConfigureAwait(false); Format.Code(chnl.Name)).ConfigureAwait(false);
} }
else else
{ {
await ReplyConfirmLocalized("cx_disable", await ReplyConfirmLocalized("cx_disable",
Format.Code(command.Aliases.First()), Format.Code(command.Name),
GetText("of_command"), GetText("of_command"),
Format.Code(chnl.Name)).ConfigureAwait(false); Format.Code(chnl.Name)).ConfigureAwait(false);
} }

View File

@ -110,6 +110,7 @@ namespace NadekoBot
//setup typereaders //setup typereaders
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader()); CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader()); CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader());
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader());
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader()); CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader());
CommandService.AddTypeReader<IGuild>(new GuildTypeReader()); CommandService.AddTypeReader<IGuild>(new GuildTypeReader());

View File

@ -29,11 +29,7 @@ namespace NadekoBot.Services
} }
public class CommandHandler public class CommandHandler
{ {
#if GLOBAL_NADEKO
public const int GlobalCommandsCooldown = 1500;
#else
public const int GlobalCommandsCooldown = 750; public const int GlobalCommandsCooldown = 750;
#endif
private readonly DiscordShardedClient _client; private readonly DiscordShardedClient _client;
private readonly CommandService _commandService; private readonly CommandService _commandService;
@ -274,9 +270,47 @@ namespace NadekoBot.Services
// maybe this message is a custom reaction // maybe this message is a custom reaction
// todo log custom reaction executions. return struct with info // todo log custom reaction executions. return struct with info
var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false);
if (crExecuted) //if it was, don't execute the command 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; return;
}
}
await cr.Send(usrMsg).ConfigureAwait(false);
}
catch (Exception ex)
{
_log.Warn("Sending CREmbed failed");
_log.Warn(ex);
}
return;
}
var exec3 = Environment.TickCount - execTime; var exec3 = Environment.TickCount - execTime;
@ -384,6 +418,7 @@ namespace NadekoBot.Services
PermissionCache pc; PermissionCache pc;
if (context.Guild != null) if (context.Guild != null)
{ {
//todo move to permissions module?
if (!Permissions.Cache.TryGetValue(context.Guild.Id, out pc)) if (!Permissions.Cache.TryGetValue(context.Guild.Id, out pc))
{ {
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())

View File

@ -12,6 +12,8 @@ namespace NadekoBot.Services.Database.Models
public string Trigger { get; set; } public string Trigger { get; set; }
public bool IsRegex { get; set; } public bool IsRegex { get; set; }
public bool OwnerOnly { get; set; } public bool OwnerOnly { get; set; }
public bool IsGlobal => !GuildId.HasValue;
} }
public class ReactionResponse : DbEntity public class ReactionResponse : DbEntity

View File

@ -32,8 +32,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl
/// <summary> /// <summary>
/// Gets and creates if it doesn't exist a config for a guild. /// Gets and creates if it doesn't exist a config for a guild.
/// </summary> /// </summary>
/// <param name="guildId"></param> /// <param name="guildId">For which guild</param>
/// <returns></returns> /// <param name="includes">Use to manipulate the set however you want</param>
/// <returns>Config for the guild</returns>
public GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null) public GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null)
{ {
GuildConfig config; GuildConfig config;

View File

@ -1,6 +1,8 @@
using Discord.Commands; using Discord.Commands;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NadekoBot.Modules.CustomReactions;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.TypeReaders namespace NadekoBot.TypeReaders
{ {
@ -17,4 +19,46 @@ namespace NadekoBot.TypeReaders
return Task.FromResult(TypeReaderResult.FromSuccess(cmd)); return Task.FromResult(TypeReaderResult.FromSuccess(cmd));
} }
} }
public class CommandOrCrTypeReader : CommandTypeReader
{
public override async Task<TypeReaderResult> 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;
}
}
} }