Prefix stuff almost complete, and i just realized permissions are getting screwed because of this
This commit is contained in:
		@@ -1,4 +1,5 @@
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
using NadekoBot.Services.CustomReactions;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@@ -8,18 +9,22 @@ namespace NadekoBot.TypeReaders
 | 
			
		||||
    public class CommandTypeReader : TypeReader
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CommandService _cmds;
 | 
			
		||||
        private readonly CommandHandler _cmdHandler;
 | 
			
		||||
 | 
			
		||||
        public CommandTypeReader(CommandService cmds)
 | 
			
		||||
        public CommandTypeReader(CommandService cmds, CommandHandler cmdHandler)
 | 
			
		||||
        {
 | 
			
		||||
            _cmds = cmds;
 | 
			
		||||
            _cmdHandler = cmdHandler;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override Task<TypeReaderResult> Read(ICommandContext context, string input)
 | 
			
		||||
        {
 | 
			
		||||
            input = input.ToUpperInvariant();
 | 
			
		||||
            if (!input.StartsWith(NadekoBot.Prefix.ToUpperInvariant()))
 | 
			
		||||
            var prefix = _cmdHandler.GetPrefix(context.Guild);
 | 
			
		||||
            if (!input.StartsWith(prefix.ToUpperInvariant()))
 | 
			
		||||
                return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
 | 
			
		||||
 | 
			
		||||
            input = input.Substring(NadekoBot.Prefix.Length);
 | 
			
		||||
            input = input.Substring(prefix.Length);
 | 
			
		||||
 | 
			
		||||
            var cmd = _cmds.Commands.FirstOrDefault(c => 
 | 
			
		||||
                c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
 | 
			
		||||
@@ -34,7 +39,7 @@ namespace NadekoBot.TypeReaders
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CustomReactionsService _crs;
 | 
			
		||||
 | 
			
		||||
        public CommandOrCrTypeReader(CustomReactionsService crs, CommandService cmds) : base(cmds)
 | 
			
		||||
        public CommandOrCrTypeReader(CustomReactionsService crs, CommandService cmds, CommandHandler cmdHandler) : base(cmds, cmdHandler)
 | 
			
		||||
        {
 | 
			
		||||
            _crs = crs;
 | 
			
		||||
        }
 | 
			
		||||
@@ -62,7 +67,7 @@ namespace NadekoBot.TypeReaders
 | 
			
		||||
            var cmd = await base.Read(context, input);
 | 
			
		||||
            if (cmd.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First()));
 | 
			
		||||
                return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
 | 
			
		||||
            }
 | 
			
		||||
            return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1560
									
								
								src/NadekoBot/Migrations/20170530033406_guild-prefixes.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1560
									
								
								src/NadekoBot/Migrations/20170530033406_guild-prefixes.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										34
									
								
								src/NadekoBot/Migrations/20170530033406_guild-prefixes.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/NadekoBot/Migrations/20170530033406_guild-prefixes.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Migrations;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Migrations
 | 
			
		||||
{
 | 
			
		||||
    public partial class guildprefixes : Migration
 | 
			
		||||
    {
 | 
			
		||||
        protected override void Up(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.AddColumn<string>(
 | 
			
		||||
                name: "Prefix",
 | 
			
		||||
                table: "GuildConfigs",
 | 
			
		||||
                nullable: true);
 | 
			
		||||
 | 
			
		||||
            migrationBuilder.AddColumn<string>(
 | 
			
		||||
                name: "DefaultPrefix",
 | 
			
		||||
                table: "BotConfig",
 | 
			
		||||
                nullable: true,
 | 
			
		||||
                defaultValue: ".");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void Down(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.DropColumn(
 | 
			
		||||
                name: "Prefix",
 | 
			
		||||
                table: "GuildConfigs");
 | 
			
		||||
 | 
			
		||||
            migrationBuilder.DropColumn(
 | 
			
		||||
                name: "DefaultPrefix",
 | 
			
		||||
                table: "BotConfig");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Infrastructure;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Metadata;
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Migrations;
 | 
			
		||||
using NadekoBot.Services.Database;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Migrations
 | 
			
		||||
{
 | 
			
		||||
@@ -149,6 +151,8 @@ namespace NadekoBot.Migrations
 | 
			
		||||
 | 
			
		||||
                    b.Property<DateTime?>("DateAdded");
 | 
			
		||||
 | 
			
		||||
                    b.Property<string>("DefaultPrefix");
 | 
			
		||||
 | 
			
		||||
                    b.Property<string>("ErrorColor");
 | 
			
		||||
 | 
			
		||||
                    b.Property<bool>("ForwardMessages");
 | 
			
		||||
@@ -568,6 +572,8 @@ namespace NadekoBot.Migrations
 | 
			
		||||
 | 
			
		||||
                    b.Property<string>("PermissionRole");
 | 
			
		||||
 | 
			
		||||
                    b.Property<string>("Prefix");
 | 
			
		||||
 | 
			
		||||
                    b.Property<int?>("RootPermissionId");
 | 
			
		||||
 | 
			
		||||
                    b.Property<bool>("SendChannelByeMessage");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Attributes;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
using NadekoBot.Services.Administration;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration
 | 
			
		||||
{
 | 
			
		||||
    public partial class Administration
 | 
			
		||||
    {
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class PrefixCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [Priority(0)]
 | 
			
		||||
            public new async Task Prefix()
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyConfirmLocalized("prefix_current", Format.Code(_cmdHandler.GetPrefix(Context.Guild))).ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.Administrator)]
 | 
			
		||||
            [Priority(1)]
 | 
			
		||||
            public new async Task Prefix([Remainder]string prefix)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var oldPrefix = base.Prefix;
 | 
			
		||||
                var newPrefix = _cmdHandler.SetPrefix(Context.Guild, prefix);
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalized("prefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task DefPrefix([Remainder]string prefix)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyConfirmLocalized("defprefix_current", _cmdHandler.DefaultPrefix).ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var oldPrefix = _cmdHandler.DefaultPrefix;
 | 
			
		||||
                var newPrefix = _cmdHandler.SetDefaultPrefix(prefix);
 | 
			
		||||
 | 
			
		||||
                await ReplyConfirmLocalized("defprefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,14 +22,16 @@ namespace NadekoBot.Modules.Games.Models
 | 
			
		||||
        private readonly List<ulong> finishedUserIds;
 | 
			
		||||
        private readonly DiscordShardedClient _client;
 | 
			
		||||
        private readonly GamesService _games;
 | 
			
		||||
        private readonly string _prefix;
 | 
			
		||||
 | 
			
		||||
        private Logger _log { get; }
 | 
			
		||||
 | 
			
		||||
        public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel)
 | 
			
		||||
        public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel, string prefix) //kek@prefix
 | 
			
		||||
        {
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            _games = games;
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _prefix = prefix;
 | 
			
		||||
 | 
			
		||||
            this.Channel = channel;
 | 
			
		||||
            IsActive = false;
 | 
			
		||||
@@ -96,7 +98,7 @@ namespace NadekoBot.Modules.Games.Models
 | 
			
		||||
            if (_games.TypingArticles.Any())
 | 
			
		||||
                return _games.TypingArticles[new NadekoRandom().Next(0, _games.TypingArticles.Count)].Text;
 | 
			
		||||
            else
 | 
			
		||||
                return $"No typing articles found. Use {NadekoBot.Prefix}typeadd command to add a new article for typing.";
 | 
			
		||||
                return $"No typing articles found. Use {_prefix}typeadd command to add a new article for typing.";
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)Context.Channel;
 | 
			
		||||
 | 
			
		||||
                var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel));
 | 
			
		||||
                var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel, Prefix));
 | 
			
		||||
 | 
			
		||||
                if (game.IsActive)
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ using System.IO;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Services.Permissions;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Help
 | 
			
		||||
{
 | 
			
		||||
@@ -20,15 +21,17 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        private readonly IBotCredentials _creds;
 | 
			
		||||
        private readonly BotConfig _config;
 | 
			
		||||
        private readonly CommandService _cmds;
 | 
			
		||||
        private readonly GlobalPermissionService _perms;
 | 
			
		||||
 | 
			
		||||
        public string HelpString => String.Format(_config.HelpString, _creds.ClientId, NadekoBot.Prefix);
 | 
			
		||||
        public string HelpString => String.Format(_config.HelpString, _creds.ClientId, Prefix);
 | 
			
		||||
        public string DMHelpString => _config.DMHelpString;
 | 
			
		||||
 | 
			
		||||
        public Help(IBotCredentials creds, BotConfig config, CommandService cmds)
 | 
			
		||||
        public Help(IBotCredentials creds, GlobalPermissionService perms, BotConfig config, CommandService cmds)
 | 
			
		||||
        {
 | 
			
		||||
            _creds = creds;
 | 
			
		||||
            _config = config;
 | 
			
		||||
            _cmds = cmds;
 | 
			
		||||
            _perms = perms;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
@@ -39,8 +42,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
                .WithTitle(GetText("list_of_modules"))
 | 
			
		||||
                .WithDescription(string.Join("\n",
 | 
			
		||||
                                     _cmds.Modules.GroupBy(m => m.GetTopLevelModule())
 | 
			
		||||
                                        //todo perms
 | 
			
		||||
                                         //.Where(m => !Permissions.Permissions.GlobalPermissionCommands.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
 | 
			
		||||
                                         .Where(m => !_perms.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
 | 
			
		||||
                                         .Select(m => "• " + m.Key.Name)
 | 
			
		||||
                                         .OrderBy(s => s)));
 | 
			
		||||
            await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
@@ -55,8 +57,7 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(module))
 | 
			
		||||
                return;
 | 
			
		||||
            var cmds = _cmds.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module))
 | 
			
		||||
                                                    //todo perms
 | 
			
		||||
                                                  //.Where(c => !Permissions.Permissions.GlobalPermissionCommands.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
 | 
			
		||||
                                                .Where(c => !_perms.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
 | 
			
		||||
                                                  .OrderBy(c => c.Aliases.First())
 | 
			
		||||
                                                  .Distinct(new CommandTextEqualityComparer())
 | 
			
		||||
                                                  .AsEnumerable();
 | 
			
		||||
@@ -154,8 +155,8 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
                    lastModule = module.Name;
 | 
			
		||||
                }
 | 
			
		||||
                helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} |" +
 | 
			
		||||
                                   $" {string.Format(com.Summary, NadekoBot.Prefix)} {GetCommandRequirements(com)} |" +
 | 
			
		||||
                                   $" {string.Format(com.Remarks, NadekoBot.Prefix)}");
 | 
			
		||||
                                   $" {string.Format(com.Summary, Prefix)} {GetCommandRequirements(com)} |" +
 | 
			
		||||
                                   $" {string.Format(com.Remarks, Prefix)}");
 | 
			
		||||
            }
 | 
			
		||||
            File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
 | 
			
		||||
            await ReplyConfirmLocalized("commandlist_regen").ConfigureAwait(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
using Discord.Commands;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
using NadekoBot.Services.Administration;
 | 
			
		||||
using NLog;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
@@ -12,19 +13,21 @@ namespace NadekoBot.Modules
 | 
			
		||||
    {
 | 
			
		||||
        protected readonly Logger _log;
 | 
			
		||||
        protected CultureInfo _cultureInfo;
 | 
			
		||||
        public readonly string Prefix;
 | 
			
		||||
        
 | 
			
		||||
        public readonly string ModuleTypeName;
 | 
			
		||||
        public readonly string LowerModuleTypeName;
 | 
			
		||||
        
 | 
			
		||||
        public NadekoStrings _strings { get; set; }
 | 
			
		||||
        public CommandHandler _cmdHandler { get; set; }
 | 
			
		||||
        public ILocalization _localization { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string Prefix => _cmdHandler.GetPrefix(Context.Guild);
 | 
			
		||||
 | 
			
		||||
        protected NadekoTopLevelModule(bool isTopLevelModule = true)
 | 
			
		||||
        {
 | 
			
		||||
            //if it's top level module
 | 
			
		||||
            ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
 | 
			
		||||
            LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
 | 
			
		||||
            Prefix = NadekoBot.Prefix;
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,11 @@ namespace NadekoBot.Modules.Permissions.Commands
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class ResetPermissionsCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            private readonly PermissionsService _service;
 | 
			
		||||
            private readonly PermissionService _service;
 | 
			
		||||
            private readonly DbService _db;
 | 
			
		||||
            private readonly GlobalPermissionService _globalPerms;
 | 
			
		||||
 | 
			
		||||
            public ResetPermissionsCommands(PermissionsService service, GlobalPermissionService globalPerms, DbService db)
 | 
			
		||||
            public ResetPermissionsCommands(PermissionService service, GlobalPermissionService globalPerms, DbService db)
 | 
			
		||||
            {
 | 
			
		||||
                _service = service;
 | 
			
		||||
                _db = db;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,9 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
    public partial class Permissions : NadekoTopLevelModule
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
        private readonly PermissionsService _service;
 | 
			
		||||
        private readonly PermissionService _service;
 | 
			
		||||
 | 
			
		||||
        public Permissions(PermissionsService service, DbService db)
 | 
			
		||||
        public Permissions(PermissionService service, DbService db)
 | 
			
		||||
        {
 | 
			
		||||
            _db = db;
 | 
			
		||||
            _service = service;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public async Task Placelist()
 | 
			
		||||
            {
 | 
			
		||||
                await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.Prefix), 
 | 
			
		||||
                await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", Prefix), 
 | 
			
		||||
                    typesStr)
 | 
			
		||||
                             .ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var rem = (_patreon.Interval - (DateTime.UtcNow - _patreon.LastUpdate));
 | 
			
		||||
                var helpcmd = Format.Code(NadekoBot.Prefix + "donate");
 | 
			
		||||
                var helpcmd = Format.Code(Prefix + "donate");
 | 
			
		||||
                await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
 | 
			
		||||
                    .WithDescription(GetText("clpa_fail"))
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already")))
 | 
			
		||||
 
 | 
			
		||||
@@ -41,9 +41,6 @@ namespace NadekoBot
 | 
			
		||||
        public static Color OkColor { get; private set; }
 | 
			
		||||
        public static Color ErrorColor { get; private set; }
 | 
			
		||||
 | 
			
		||||
        //todo placeholder, will be guild-based
 | 
			
		||||
        public static string Prefix { get; } = ".";
 | 
			
		||||
 | 
			
		||||
        public ImmutableArray<GuildConfig> AllGuildConfigs { get; }
 | 
			
		||||
        public BotConfig BotConfig { get; }
 | 
			
		||||
        public DbService Db { get; }
 | 
			
		||||
@@ -97,7 +94,7 @@ namespace NadekoBot
 | 
			
		||||
            var soundcloudApiService = new SoundCloudApiService(Credentials);
 | 
			
		||||
            var localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
 | 
			
		||||
            var strings = new NadekoStrings(localization);
 | 
			
		||||
            var commandHandler = new CommandHandler(Client, CommandService, Credentials, this);
 | 
			
		||||
            var commandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this);
 | 
			
		||||
            var stats = new StatsService(Client, commandHandler, Credentials);
 | 
			
		||||
            var images = new ImagesService();
 | 
			
		||||
            var currencyHandler = new CurrencyService(BotConfig, Db);
 | 
			
		||||
@@ -112,6 +109,14 @@ namespace NadekoBot
 | 
			
		||||
            var commandMapService = new CommandMapService(AllGuildConfigs);
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region permissions
 | 
			
		||||
            var permissionsService = new PermissionService(Db, BotConfig);
 | 
			
		||||
            var blacklistService = new BlacklistService(BotConfig);
 | 
			
		||||
            var cmdcdsService = new CmdCdService(AllGuildConfigs);
 | 
			
		||||
            var filterService = new FilterService(Client, AllGuildConfigs);
 | 
			
		||||
            var globalPermsService = new GlobalPermissionService(BotConfig);
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            #region Searches
 | 
			
		||||
            var searchesService = new SearchesService(Client, googleApiService, Db);
 | 
			
		||||
            var streamNotificationService = new StreamNotificationService(Db, Client, strings);
 | 
			
		||||
@@ -119,12 +124,12 @@ namespace NadekoBot
 | 
			
		||||
 | 
			
		||||
            var clashService = new ClashOfClansService(Client, Db, localization, strings);
 | 
			
		||||
            var musicService = new MusicService(googleApiService, strings, localization, Db, soundcloudApiService, Credentials, AllGuildConfigs);
 | 
			
		||||
            var crService = new CustomReactionsService(Db, Client);
 | 
			
		||||
            var crService = new CustomReactionsService(permissionsService, Db, Client);
 | 
			
		||||
            var helpService = new HelpService(BotConfig);
 | 
			
		||||
 | 
			
		||||
            #region Games
 | 
			
		||||
            var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, strings, images);
 | 
			
		||||
            var chatterBotService = new ChatterBotService(Client, AllGuildConfigs);
 | 
			
		||||
            var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, strings, images, commandHandler);
 | 
			
		||||
            var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs);
 | 
			
		||||
            var pollService = new PollService(Client, strings);
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
@@ -140,13 +145,9 @@ namespace NadekoBot
 | 
			
		||||
            var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService);
 | 
			
		||||
            var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs);
 | 
			
		||||
            var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs);
 | 
			
		||||
            var permissionsService = new PermissionsService(Db, BotConfig);
 | 
			
		||||
            var blacklistService = new BlacklistService(BotConfig);
 | 
			
		||||
            var cmdcdsService = new CmdCdService(AllGuildConfigs);
 | 
			
		||||
            var filterService = new FilterService(Client, AllGuildConfigs);
 | 
			
		||||
            var globalPermsService = new GlobalPermissionService(BotConfig);
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            //initialize Services
 | 
			
		||||
            Services = new NServiceProvider.ServiceProviderBuilder()
 | 
			
		||||
                .Add<ILocalization>(localization)
 | 
			
		||||
@@ -188,7 +189,7 @@ namespace NadekoBot
 | 
			
		||||
                    .Add(gameVcService)
 | 
			
		||||
                    .Add(autoAssignRoleService)
 | 
			
		||||
                    .Add(protectionService)
 | 
			
		||||
                .Add<PermissionsService>(permissionsService)
 | 
			
		||||
                .Add<PermissionService>(permissionsService)
 | 
			
		||||
                    .Add(blacklistService)
 | 
			
		||||
                    .Add(cmdcdsService)
 | 
			
		||||
                    .Add(filterService)
 | 
			
		||||
@@ -199,8 +200,8 @@ namespace NadekoBot
 | 
			
		||||
 | 
			
		||||
            //setup typereaders
 | 
			
		||||
            CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
 | 
			
		||||
            CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService));
 | 
			
		||||
            CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService));
 | 
			
		||||
            CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService, commandHandler));
 | 
			
		||||
            CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService, commandHandler));
 | 
			
		||||
            CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
 | 
			
		||||
            CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
 | 
			
		||||
            CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\Migration\MigrationException.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\MuteCommands.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\PlayingRotateCommands.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\PrefixCommands.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\ProtectionCommands.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
 | 
			
		||||
    <Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
 | 
			
		||||
 
 | 
			
		||||
@@ -3474,4 +3474,22 @@
 | 
			
		||||
  <data name="resetglobalpermissions_usage" xml:space="preserve">
 | 
			
		||||
    <value>`{0}resetglobalperms`</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="prefix_cmd" xml:space="preserve">
 | 
			
		||||
    <value>prefix</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="prefix_usage" xml:space="preserve">
 | 
			
		||||
    <value>`{0}prefix +`</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="prefix_desc" xml:space="preserve">
 | 
			
		||||
    <value>Sets this server's prefix for all bot commands. Provide no arguments to see the current server prefix.</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="defprefix_cmd" xml:space="preserve">
 | 
			
		||||
    <value>defprefix</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="defprefix_usage" xml:space="preserve">
 | 
			
		||||
    <value>`{0}defprefix +`</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="defprefix_desc" xml:space="preserve">
 | 
			
		||||
    <value>Sets bot's default prefix for all bot commands. Provide no arguments to see the current default prefix. This will not change this server's current prefix.</value>
 | 
			
		||||
  </data>
 | 
			
		||||
</root>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using NLog;
 | 
			
		||||
using System;
 | 
			
		||||
@@ -33,9 +34,10 @@ namespace NadekoBot.Services.Administration
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _db = db;
 | 
			
		||||
 | 
			
		||||
            GuildMuteRoles = new ConcurrentDictionary<ulong, string>(gcs
 | 
			
		||||
            GuildMuteRoles = gcs
 | 
			
		||||
                    .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
 | 
			
		||||
                    .ToDictionary(c => c.GuildId, c => c.MuteRoleName));
 | 
			
		||||
                    .ToDictionary(c => c.GuildId, c => c.MuteRoleName)
 | 
			
		||||
                    .ToConcurrent();
 | 
			
		||||
 | 
			
		||||
            MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(gcs.ToDictionary(
 | 
			
		||||
                k => k.GuildId,
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ using System.Threading;
 | 
			
		||||
using NadekoBot.DataStructures;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
using NadekoBot.DataStructures.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services
 | 
			
		||||
{
 | 
			
		||||
@@ -31,6 +33,8 @@ namespace NadekoBot.Services
 | 
			
		||||
        private readonly IBotCredentials _creds;
 | 
			
		||||
        private readonly NadekoBot _bot;
 | 
			
		||||
        private INServiceProvider _services;
 | 
			
		||||
        public string DefaultPrefix { get; private set; }
 | 
			
		||||
        private ConcurrentDictionary<ulong, string> _prefixes { get; } = new ConcurrentDictionary<ulong, string>();
 | 
			
		||||
 | 
			
		||||
        private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels { get; set; } = new ImmutableArray<AsyncLazy<IDMChannel>>();
 | 
			
		||||
 | 
			
		||||
@@ -42,12 +46,13 @@ namespace NadekoBot.Services
 | 
			
		||||
        public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
 | 
			
		||||
        private readonly Timer _clearUsersOnShortCooldown;
 | 
			
		||||
 | 
			
		||||
        public CommandHandler(DiscordShardedClient client, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
 | 
			
		||||
        public CommandHandler(DiscordShardedClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
 | 
			
		||||
        {
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _commandService = commandService;
 | 
			
		||||
            _creds = credentials;
 | 
			
		||||
            _bot = bot;
 | 
			
		||||
            _db = db;
 | 
			
		||||
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
@@ -55,8 +60,60 @@ namespace NadekoBot.Services
 | 
			
		||||
            {
 | 
			
		||||
                UsersOnShortCooldown.Clear();
 | 
			
		||||
            }, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
 | 
			
		||||
 | 
			
		||||
            DefaultPrefix = bc.DefaultPrefix;
 | 
			
		||||
            _prefixes = gcs
 | 
			
		||||
                .Where(x => x.Prefix != null)
 | 
			
		||||
                .ToDictionary(x => x.GuildId, x => x.Prefix)
 | 
			
		||||
                .ToConcurrent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetPrefix(IGuild guild) => GetPrefix(guild?.Id);
 | 
			
		||||
 | 
			
		||||
        public string GetPrefix(ulong? id)
 | 
			
		||||
        {
 | 
			
		||||
            if (id == null || !_prefixes.TryGetValue(id.Value, out var prefix))
 | 
			
		||||
                return DefaultPrefix;
 | 
			
		||||
 | 
			
		||||
            return prefix;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string SetDefaultPrefix(string prefix)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                throw new ArgumentNullException(nameof(prefix));
 | 
			
		||||
 | 
			
		||||
            prefix = prefix.ToLowerInvariant();
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
            {
 | 
			
		||||
                uow.BotConfig.GetOrCreate(set => set).DefaultPrefix = prefix;
 | 
			
		||||
                uow.Complete();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return DefaultPrefix = prefix;
 | 
			
		||||
        }
 | 
			
		||||
        public string SetPrefix(IGuild guild, string prefix)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(prefix))
 | 
			
		||||
                throw new ArgumentNullException(nameof(prefix));
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
                throw new ArgumentNullException(nameof(guild));
 | 
			
		||||
 | 
			
		||||
            prefix = prefix.ToLowerInvariant();
 | 
			
		||||
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
            {
 | 
			
		||||
                var gc = uow.GuildConfigs.For(guild.Id, set => set);
 | 
			
		||||
                gc.Prefix = prefix;
 | 
			
		||||
                uow.Complete();
 | 
			
		||||
            }
 | 
			
		||||
            _prefixes.AddOrUpdate(guild.Id, prefix, (key, old) => prefix);
 | 
			
		||||
 | 
			
		||||
            return prefix;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void AddServices(INServiceProvider services)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
@@ -87,13 +144,14 @@ namespace NadekoBot.Services
 | 
			
		||||
 | 
			
		||||
        public Task StartHandling()
 | 
			
		||||
        {
 | 
			
		||||
            _client.MessageReceived += MessageReceivedHandler;
 | 
			
		||||
            _client.MessageReceived += (msg) => { var _ = Task.Run(() => MessageReceivedHandler(msg)); return Task.CompletedTask; };
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private const float _oneThousandth = 1.0f / 1000;
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
 | 
			
		||||
        private Task LogSuccessfulExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        private Task LogSuccessfulExecution(IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        {
 | 
			
		||||
            _log.Info("Command Executed after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
 | 
			
		||||
                        "User: {0}\n\t" +
 | 
			
		||||
@@ -108,7 +166,7 @@ namespace NadekoBot.Services
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LogErroredExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        private void LogErroredExecution(string errorMessage, IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
 | 
			
		||||
        {
 | 
			
		||||
            _log.Warn("Command Errored after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
 | 
			
		||||
                        "User: {0}\n\t" +
 | 
			
		||||
@@ -120,7 +178,7 @@ namespace NadekoBot.Services
 | 
			
		||||
                        (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                        (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                        usrMsg.Content,// {3}
 | 
			
		||||
                        exec
 | 
			
		||||
                        errorMessage
 | 
			
		||||
                        //exec.Result.ErrorReason // {4}
 | 
			
		||||
                        );
 | 
			
		||||
        }
 | 
			
		||||
@@ -199,33 +257,25 @@ namespace NadekoBot.Services
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var prefix = GetPrefix(guild.Id);
 | 
			
		||||
            // execute the command and measure the time it took
 | 
			
		||||
            if (messageContent.StartsWith(NadekoBot.Prefix))
 | 
			
		||||
            if (messageContent.StartsWith(prefix))
 | 
			
		||||
            {
 | 
			
		||||
                var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
 | 
			
		||||
                var result = await ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, prefix.Length, _services, MultiMatchHandling.Best);
 | 
			
		||||
                execTime = Environment.TickCount - execTime;
 | 
			
		||||
                
 | 
			
		||||
                ////todo commandHandler
 | 
			
		||||
                if (exec)
 | 
			
		||||
                if (result.Success)
 | 
			
		||||
                {
 | 
			
		||||
                    //    await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
 | 
			
		||||
                    await LogSuccessfulExecution(usrMsg, exec, channel as ITextChannel, exec2, exec3, execTime).ConfigureAwait(false);
 | 
			
		||||
                    await LogSuccessfulExecution(usrMsg, channel as ITextChannel, exec2, exec3, execTime).ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                //else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
 | 
			
		||||
                //{
 | 
			
		||||
                //    LogErroredExecution(usrMsg, exec, channel, exec2, exec3, execTime);
 | 
			
		||||
                //    if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
 | 
			
		||||
                //    {
 | 
			
		||||
                //        if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
 | 
			
		||||
                //            try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
 | 
			
		||||
                //    }
 | 
			
		||||
                //    return;
 | 
			
		||||
                //}
 | 
			
		||||
 | 
			
		||||
                if (exec)
 | 
			
		||||
                    return;
 | 
			
		||||
                else if (result.Error != null)
 | 
			
		||||
                {
 | 
			
		||||
                    //todo 80 should have log levels and it should return some kind of result, 
 | 
			
		||||
                    // instead of tuple with the type of thing that went wrong, like before
 | 
			
		||||
                    LogErroredExecution(result.Error, usrMsg,  channel as ITextChannel, exec2, exec3, execTime);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -239,15 +289,15 @@ namespace NadekoBot.Services
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Task<bool> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
        public Task<(bool Success, string Error)> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
            => ExecuteCommand(context, input.Substring(argPos), serviceProvider, multiMatchHandling);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
        public async Task<(bool Success, string Error)> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
 | 
			
		||||
        {
 | 
			
		||||
            var searchResult = _commandService.Search(context, input);
 | 
			
		||||
            if (!searchResult.IsSuccess)
 | 
			
		||||
                return false;
 | 
			
		||||
                return (false, null);
 | 
			
		||||
 | 
			
		||||
            var commands = searchResult.Commands;
 | 
			
		||||
            for (int i = commands.Count - 1; i >= 0; i--)
 | 
			
		||||
@@ -256,7 +306,7 @@ namespace NadekoBot.Services
 | 
			
		||||
                if (!preconditionResult.IsSuccess)
 | 
			
		||||
                {
 | 
			
		||||
                    if (commands.Count == 1)
 | 
			
		||||
                        return false;
 | 
			
		||||
                        return (false, null);
 | 
			
		||||
                    else
 | 
			
		||||
                        continue;
 | 
			
		||||
                }
 | 
			
		||||
@@ -280,33 +330,18 @@ namespace NadekoBot.Services
 | 
			
		||||
                    if (!parseResult.IsSuccess)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (commands.Count == 1)
 | 
			
		||||
                            return false;
 | 
			
		||||
                            return (false, null);
 | 
			
		||||
                        else
 | 
			
		||||
                            continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var cmd = commands[i].Command;
 | 
			
		||||
                var resetCommand = cmd.Name == "resetperms";
 | 
			
		||||
                var module = cmd.Module.GetTopLevelModule();
 | 
			
		||||
                if (context.Guild != null)
 | 
			
		||||
                {
 | 
			
		||||
                    //////future
 | 
			
		||||
                    ////int price;
 | 
			
		||||
                    ////if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
 | 
			
		||||
                    ////{
 | 
			
		||||
                    ////    var success = await _cs.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
 | 
			
		||||
                    ////    if (!success)
 | 
			
		||||
                    ////    {
 | 
			
		||||
                    ////        return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command."));
 | 
			
		||||
                    ////    }
 | 
			
		||||
                    ////}
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Bot will ignore commands which are ran more often than what specified by
 | 
			
		||||
                // GlobalCommandsCooldown constant (miliseconds)
 | 
			
		||||
                if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
 | 
			
		||||
                    return false;
 | 
			
		||||
                    return (false, null);
 | 
			
		||||
                //return SearchResult.FromError(CommandError.Exception, "You are on a global cooldown.");
 | 
			
		||||
 | 
			
		||||
                var commandName = cmd.Aliases.First();
 | 
			
		||||
@@ -316,15 +351,17 @@ namespace NadekoBot.Services
 | 
			
		||||
                        await exec.TryBlockLate(_client, context.Message, context.Guild, context.Channel, context.User, cmd.Module.GetTopLevelModule().Name, commandName).ConfigureAwait(false))
 | 
			
		||||
                    {
 | 
			
		||||
                        _log.Info("Late blocking User [{0}] Command: [{1}] in [{2}]", context.User, commandName, svc.GetType().Name);
 | 
			
		||||
                        return false;
 | 
			
		||||
                        return (false, null);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
 | 
			
		||||
                return true;
 | 
			
		||||
                var execResult = await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
 | 
			
		||||
                if (execResult.Exception != null) //todo temp, to not be blind
 | 
			
		||||
                    _log.Warn(execResult.Exception);
 | 
			
		||||
                return (true, null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
            return (false, null);
 | 
			
		||||
            //return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ using System.Linq;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using NadekoBot.Services.Permissions;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.CustomReactions
 | 
			
		||||
{
 | 
			
		||||
@@ -22,9 +23,9 @@ namespace NadekoBot.Services.CustomReactions
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
        private readonly DiscordShardedClient _client;
 | 
			
		||||
        private readonly PermissionsService _perms;
 | 
			
		||||
        private readonly PermissionService _perms;
 | 
			
		||||
 | 
			
		||||
        public CustomReactionsService(PermissionsService perms, DbService db, DiscordShardedClient client)
 | 
			
		||||
        public CustomReactionsService(PermissionService perms, DbService db, DiscordShardedClient client)
 | 
			
		||||
        {
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            _db = db;
 | 
			
		||||
@@ -100,16 +101,18 @@ namespace NadekoBot.Services.CustomReactions
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    //todo permissions
 | 
			
		||||
                    if (guild is SocketGuild sg)
 | 
			
		||||
                    {
 | 
			
		||||
                        PermissionCache pc = _perms.GetCache(guild.Id);
 | 
			
		||||
 | 
			
		||||
                        var pc = _perms.GetCache(guild.Id);
 | 
			
		||||
                        if (!pc.Permissions.CheckPermissions(msg, cr.Trigger, "ActualCustomReactions",
 | 
			
		||||
                            out int index))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (pc.Verbose)
 | 
			
		||||
                            {
 | 
			
		||||
                                var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(sg)}** is preventing this action.";
 | 
			
		||||
                                try { await msg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
 | 
			
		||||
                                _log.Info(returnMsg);
 | 
			
		||||
                            }
 | 
			
		||||
                            return true;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@ Nadeko Support Server: https://discord.gg/nadekobot";
 | 
			
		||||
        public HashSet<BlockedCmdOrMdl> BlockedCommands { get; set; }
 | 
			
		||||
        public HashSet<BlockedCmdOrMdl> BlockedModules { get; set; }
 | 
			
		||||
        public int PermissionVersion { get; set; } = 1;
 | 
			
		||||
        public string DefaultPrefix { get; set; } = ".";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class BlockedCmdOrMdl : DbEntity
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,9 @@ namespace NadekoBot.Services.Database.Models
 | 
			
		||||
    public class GuildConfig : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong GuildId { get; set; }
 | 
			
		||||
 | 
			
		||||
        public string Prefix { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
        public bool DeleteMessageOnCommand { get; set; }
 | 
			
		||||
        public ulong AutoAssignRoleId { get; set; }
 | 
			
		||||
        //greet stuff
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.DataStructures.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Services.Permissions;
 | 
			
		||||
using NLog;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
@@ -16,13 +17,15 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DiscordShardedClient _client;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
        private readonly PermissionService _perms;
 | 
			
		||||
 | 
			
		||||
        public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; }
 | 
			
		||||
 | 
			
		||||
        public ChatterBotService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
 | 
			
		||||
        public ChatterBotService(DiscordShardedClient client, PermissionService perms, IEnumerable<GuildConfig> gcs)
 | 
			
		||||
        {
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            _perms = perms;
 | 
			
		||||
 | 
			
		||||
            ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
 | 
			
		||||
                    gcs.Where(gc => gc.CleverbotEnabled)
 | 
			
		||||
@@ -80,7 +83,7 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
 | 
			
		||||
        public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg)
 | 
			
		||||
        {
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
            if (!(guild is SocketGuild sg))
 | 
			
		||||
                return false;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -88,19 +91,21 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
                if (message == null || cbs == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
                
 | 
			
		||||
                //todo permissions
 | 
			
		||||
                //PermissionCache pc = Permissions.GetCache(guild.Id);
 | 
			
		||||
                //if (!pc.Permissions.CheckPermissions(usrMsg,
 | 
			
		||||
                //    NadekoBot.Prefix + "cleverbot",
 | 
			
		||||
                //    "Games".ToLowerInvariant(),
 | 
			
		||||
                //    out int index))
 | 
			
		||||
                //{
 | 
			
		||||
                //    //todo 46 print in guild actually
 | 
			
		||||
                //    var returnMsg =
 | 
			
		||||
                //        $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
 | 
			
		||||
                //    _log.Info(returnMsg);
 | 
			
		||||
                //    return true;
 | 
			
		||||
                //}
 | 
			
		||||
                var pc = _perms.GetCache(guild.Id);
 | 
			
		||||
                if (!pc.Permissions.CheckPermissions(usrMsg,
 | 
			
		||||
                    "cleverbot",
 | 
			
		||||
                    "Games".ToLowerInvariant(),
 | 
			
		||||
                    out int index))
 | 
			
		||||
                {
 | 
			
		||||
                    if (pc.Verbose)
 | 
			
		||||
                    {
 | 
			
		||||
                        //todo move this to permissions, prefix is always "." as a placeholder, fix that when you move it
 | 
			
		||||
                        var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(sg)}** is preventing this action.";
 | 
			
		||||
                        try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
 | 
			
		||||
                        _log.Info(returnMsg);
 | 
			
		||||
                    }
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var cleverbotExecuted = await TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
 | 
			
		||||
                if (cleverbotExecuted)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,15 +29,18 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        public readonly string TypingArticlesPath = "data/typing_articles2.json";
 | 
			
		||||
        private readonly CommandHandler _cmdHandler;
 | 
			
		||||
 | 
			
		||||
        public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
 | 
			
		||||
 | 
			
		||||
        public GamesService(DiscordShardedClient client, BotConfig bc, IEnumerable<GuildConfig> gcs, 
 | 
			
		||||
            NadekoStrings strings, IImagesService images)
 | 
			
		||||
            NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
 | 
			
		||||
        {
 | 
			
		||||
            _bc = bc;
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _strings = strings;
 | 
			
		||||
            _images = images;
 | 
			
		||||
            _cmdHandler = cmdHandler;
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
            //8ball
 | 
			
		||||
@@ -123,7 +126,7 @@ namespace NadekoBot.Services.Games
 | 
			
		||||
                    if (dropAmount > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        var msgs = new IUserMessage[dropAmount];
 | 
			
		||||
                        var prefix = NadekoBot.Prefix;
 | 
			
		||||
                        var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
 | 
			
		||||
                        var toSend = dropAmount == 1
 | 
			
		||||
                            ? GetText(channel, "curgen_sn", _bc.CurrencySign)
 | 
			
		||||
                                + " " + GetText(channel, "pick_sn", prefix)
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ namespace NadekoBot.Services.Music
 | 
			
		||||
                    case MusicType.Radio:
 | 
			
		||||
                        return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
 | 
			
		||||
                    case MusicType.Normal:
 | 
			
		||||
                        //todo have videoid in songinfo from the start
 | 
			
		||||
                        //todo 50 have videoid in songinfo from the start
 | 
			
		||||
                        var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
 | 
			
		||||
                        return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
 | 
			
		||||
                    case MusicType.Local:
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,7 @@ namespace NadekoBot.Services.Permissions
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return NadekoBot.Prefix + com;
 | 
			
		||||
            return "." + com;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IEnumerable<Permission> AsEnumerable(this Permission perm)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,10 +9,11 @@ using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.Permissions
 | 
			
		||||
{
 | 
			
		||||
    public class PermissionsService : ILateBlocker
 | 
			
		||||
    public class PermissionService : ILateBlocker
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
@@ -21,7 +22,7 @@ namespace NadekoBot.Services.Permissions
 | 
			
		||||
        public ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
 | 
			
		||||
            new ConcurrentDictionary<ulong, PermissionCache>();
 | 
			
		||||
 | 
			
		||||
        public PermissionsService(DbService db, BotConfig bc)
 | 
			
		||||
        public PermissionService(DbService db, BotConfig bc)
 | 
			
		||||
        {
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            _db = db;
 | 
			
		||||
@@ -177,6 +178,8 @@ namespace NadekoBot.Services.Permissions
 | 
			
		||||
                if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index))
 | 
			
		||||
                {
 | 
			
		||||
                    var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)guild)}** is preventing this action.";
 | 
			
		||||
                    if (pc.Verbose)
 | 
			
		||||
                        try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
 | 
			
		||||
                    return true;
 | 
			
		||||
                    //return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
 | 
			
		||||
                }
 | 
			
		||||
@@ -187,6 +190,9 @@ namespace NadekoBot.Services.Permissions
 | 
			
		||||
                    var roles = (user as SocketGuildUser)?.Roles ?? ((IGuildUser)user).RoleIds.Select(x => guild.GetRole(x)).Where(x => x != null);
 | 
			
		||||
                    if (!roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && user.Id != ((IGuildUser)user).Guild.OwnerId)
 | 
			
		||||
                    {
 | 
			
		||||
                        var returnMsg = $"You need the **{pc.PermRole}** role in order to use permission commands.";
 | 
			
		||||
                        if (pc.Verbose)
 | 
			
		||||
                            try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
 | 
			
		||||
                        return true;
 | 
			
		||||
                        //return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,6 @@ namespace NadekoBot.Services.Utility
 | 
			
		||||
            if (guild == null || string.IsNullOrWhiteSpace(input))
 | 
			
		||||
                return input;
 | 
			
		||||
            
 | 
			
		||||
            //todo alias mapping
 | 
			
		||||
            if (guild != null)
 | 
			
		||||
            {
 | 
			
		||||
                input = input.ToLowerInvariant();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,9 @@ namespace NadekoBot.Extensions
 | 
			
		||||
{
 | 
			
		||||
    public static class Extensions
 | 
			
		||||
    {
 | 
			
		||||
        public static ConcurrentDictionary<TKey, TValue> ToConcurrent<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dict)
 | 
			
		||||
            => new ConcurrentDictionary<TKey, TValue>(dict);
 | 
			
		||||
 | 
			
		||||
        public static bool IsAuthor(this IMessage msg, IDiscordClient client) =>
 | 
			
		||||
            msg.Author?.Id == client.CurrentUser.Id;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -165,14 +165,14 @@
 | 
			
		||||
    "administration_rc": "Color of {0} role has been changed.",
 | 
			
		||||
    "administration_rc_not_exist": "That role does not exist.",
 | 
			
		||||
    "administration_rc_params": "The parameters specified are invalid.",
 | 
			
		||||
    "administration_rc_perms": "Error occured due to invalid color or insufficient permissions.",
 | 
			
		||||
    "administration_rc_perms": "Error occurred due to invalid color or insufficient permissions.",
 | 
			
		||||
    "administration_remrole": "Successfully removed role {0} from user {1}",
 | 
			
		||||
    "administration_remrole_err": "Failed to remove role. I have insufficient permissions.",
 | 
			
		||||
    "administration_renrole": "Role renamed.",
 | 
			
		||||
    "administration_renrole_err": "Failed to rename role. I have insufficient permissions.",
 | 
			
		||||
    "administration_renrole_perms": "You can't edit roles higher than your highest role.",
 | 
			
		||||
    "administration_reprm": "Removed the playing message: {0}",
 | 
			
		||||
    "administration_role_added": "Role {0} as been added to the list.",
 | 
			
		||||
    "administration_role_added": "Role {0} has been added to the list.",
 | 
			
		||||
    "administration_role_clean": "{0} not found.Cleaned up.",
 | 
			
		||||
    "administration_role_in_list": "Role {0} is already in the list.",
 | 
			
		||||
    "administration_ropl_added": "Added.",
 | 
			
		||||
@@ -236,7 +236,7 @@
 | 
			
		||||
    "administration_vt_enabled": "Enabled voice + text feature.",
 | 
			
		||||
    "administration_vt_exit": "I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server.",
 | 
			
		||||
    "administration_vt_no_admin": "You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards.",
 | 
			
		||||
    "administration_vt_perms": "I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission)",
 | 
			
		||||
    "administration_vt_perms": "I require at least **manage roles** and **manage channels** permissions to enable this feature. (preferred Administration permission)",
 | 
			
		||||
    "administration_xmuted_text": "User {0} from text chat",
 | 
			
		||||
    "administration_xmuted_text_and_voice": "User {0} from text and voice chat",
 | 
			
		||||
    "administration_xmuted_voice": "User {0} from voice chat",
 | 
			
		||||
@@ -519,7 +519,7 @@
 | 
			
		||||
    "searches_define": "Define:",
 | 
			
		||||
    "searches_dropped": "Dropped",
 | 
			
		||||
    "searches_episodes": "Episodes",
 | 
			
		||||
    "searches_error_occured": "Error occured.",
 | 
			
		||||
    "searches_error_occured": "Error occurred.",
 | 
			
		||||
    "searches_example": "Example",
 | 
			
		||||
    "searches_failed_finding_anime": "Failed finding that animu.",
 | 
			
		||||
    "searches_failed_finding_manga": "Failed finding that mango.",
 | 
			
		||||
@@ -605,9 +605,9 @@
 | 
			
		||||
    "utility_convert_not_found": "Cannot convert {0} to {1}: units not found",
 | 
			
		||||
    "utility_convert_type_error": "Cannot convert {0} to {1}: types of unit are not equal",
 | 
			
		||||
    "utility_created_at": "Created at",
 | 
			
		||||
    "utility_chc_join": "Joined cross server channel.",
 | 
			
		||||
    "utility_chc_leave": "Left cross server channel.",
 | 
			
		||||
    "utility_chc_token": "This is your CSC token",
 | 
			
		||||
    "utility_csc_join": "Joined cross server channel.",
 | 
			
		||||
    "utility_csc_leave": "Left cross server channel.",
 | 
			
		||||
    "utility_csc_token": "This is your CSC token",
 | 
			
		||||
    "utility_custom_emojis": "Custom emojis",
 | 
			
		||||
    "utility_error": "Error",
 | 
			
		||||
    "utility_features": "Features",
 | 
			
		||||
@@ -638,7 +638,7 @@
 | 
			
		||||
    "utility_presence_txt": "{0} Servers\n{1} Text Channels\n{2} Voice Channels",
 | 
			
		||||
    "utility_quotes_deleted": "Deleted all quotes with {0} keyword.",
 | 
			
		||||
    "utility_quotes_page": "Page {0} of quotes",
 | 
			
		||||
    "utility_quotes_page_none": "No quotes found matching the quote ID specified.",
 | 
			
		||||
    "utility_quotes_page_none": "No quotes found on that page.",
 | 
			
		||||
    "utility_quotes_remove_none": "No quotes found which you can remove.",
 | 
			
		||||
    "utility_quote_added": "Quote Added",
 | 
			
		||||
    "utility_quote_deleted": "Quote #{0} deleted.",
 | 
			
		||||
@@ -779,5 +779,12 @@
 | 
			
		||||
    "permissions_gcmd_remove": "Command {0} has been enabled on all servers.",
 | 
			
		||||
    "permissions_gmod_add": "Module {0} has been disabled on all servers.",
 | 
			
		||||
    "permissions_gmod_remove": "Module {0} has been enabled on all servers.",
 | 
			
		||||
    "permissions_lgp_none": "No blocked commands or modules."
 | 
			
		||||
    "permissions_lgp_none": "No blocked commands or modules.",
 | 
			
		||||
    "gambling_animal_race_no_race": "This Animal Race is full!",
 | 
			
		||||
    "utility_cant_read_or_send": "You can't read from or send messages to that channel.",
 | 
			
		||||
  "utility_quotes_notfound": "No quotes found matching the quote ID specified.",
 | 
			
		||||
  "administration_prefix_current": "Prefix on this server is {0}",
 | 
			
		||||
  "administration_prefix_new":  "Changed prefix on this server from {0} to {1}",
 | 
			
		||||
  "administration_defprefix_current": "Default bot prefix is {0}",
 | 
			
		||||
  "administration_defprefix_new":  "Changed Default bot prefix from {0} to {1}"
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user