Merge remote-tracking branch 'Kwoth/1.9' into 1.9
This commit is contained in:
		@@ -261,7 +261,7 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
        public async Task CreatVoiChanl([Remainder] string channelName)
 | 
					        public async Task CreatVoiChanl([Remainder] string channelName)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false);
 | 
					            var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false);
 | 
				
			||||||
            await ReplyConfirmLocalized("createvoich",Format.Bold(ch.Name)).ConfigureAwait(false);
 | 
					            await ReplyConfirmLocalized("createvoich", Format.Bold(ch.Name)).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
					        [NadekoCommand, Usage, Description, Aliases]
 | 
				
			||||||
@@ -312,7 +312,7 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
        [RequireUserPermission(GuildPermission.MentionEveryone)]
 | 
					        [RequireUserPermission(GuildPermission.MentionEveryone)]
 | 
				
			||||||
        public async Task MentionRole(params IRole[] roles)
 | 
					        public async Task MentionRole(params IRole[] roles)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string send = "❕" +GetText("menrole",Context.User.Mention);
 | 
					            string send = "❕" + GetText("menrole", Context.User.Mention);
 | 
				
			||||||
            foreach (var role in roles)
 | 
					            foreach (var role in roles)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                send += $"\n**{role.Name}**\n";
 | 
					                send += $"\n**{role.Name}**\n";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,15 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
        public class UserPunishCommands : NadekoSubmodule<UserPunishService>
 | 
					        public class UserPunishCommands : NadekoSubmodule<UserPunishService>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            private readonly DbService _db;
 | 
					            private readonly DbService _db;
 | 
				
			||||||
 | 
					            private readonly CurrencyService _cs;
 | 
				
			||||||
 | 
					            private readonly IBotConfigProvider _bc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public UserPunishCommands(DbService db, MuteService muteService)
 | 
					            public UserPunishCommands(DbService db, MuteService muteService,
 | 
				
			||||||
 | 
					                CurrencyService cs, IBotConfigProvider bc)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _db = db;
 | 
					                _db = db;
 | 
				
			||||||
 | 
					                _cs = cs;
 | 
				
			||||||
 | 
					                _bc = bc;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
					            [NadekoCommand, Usage, Description, Aliases]
 | 
				
			||||||
@@ -101,7 +106,7 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                var embed = new EmbedBuilder().WithOkColor()
 | 
					                var embed = new EmbedBuilder().WithOkColor()
 | 
				
			||||||
                    .WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()))
 | 
					                    .WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()))
 | 
				
			||||||
                    .WithFooter(efb => efb.WithText(GetText("page", page  + 1)));
 | 
					                    .WithFooter(efb => efb.WithText(GetText("page", page + 1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!warnings.Any())
 | 
					                if (!warnings.Any())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -202,8 +207,8 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
                    uow.Complete();
 | 
					                    uow.Complete();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                await ReplyConfirmLocalized("warn_punish_set", 
 | 
					                await ReplyConfirmLocalized("warn_punish_set",
 | 
				
			||||||
                    Format.Bold(punish.ToString()), 
 | 
					                    Format.Bold(punish.ToString()),
 | 
				
			||||||
                    Format.Bold(number.ToString())).ConfigureAwait(false);
 | 
					                    Format.Bold(number.ToString())).ConfigureAwait(false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -397,6 +402,92 @@ namespace NadekoBot.Modules.Administration
 | 
				
			|||||||
                        .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
 | 
					                        .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
 | 
				
			||||||
                    .ConfigureAwait(false);
 | 
					                    .ConfigureAwait(false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            [NadekoCommand, Usage, Description, Aliases]
 | 
				
			||||||
 | 
					            [RequireContext(ContextType.Guild)]
 | 
				
			||||||
 | 
					            [RequireUserPermission(GuildPermission.BanMembers)]
 | 
				
			||||||
 | 
					            [RequireBotPermission(GuildPermission.BanMembers)]
 | 
				
			||||||
 | 
					            [OwnerOnly]
 | 
				
			||||||
 | 
					            public async Task MassKill([Remainder] string people)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (string.IsNullOrWhiteSpace(people))
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var gusers = ((SocketGuild)Context.Guild).Users;
 | 
				
			||||||
 | 
					                //get user objects and reasons
 | 
				
			||||||
 | 
					                var bans = people.Split("\n")
 | 
				
			||||||
 | 
					                    .Select(x =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var split = x.Trim().Split(" ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var reason = string.Join(" ", split.Skip(1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (ulong.TryParse(split[0], out var id))
 | 
				
			||||||
 | 
					                            return (Original: split[0], Id: id, Reason: reason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        return (Original: split[0], 
 | 
				
			||||||
 | 
					                            Id: gusers
 | 
				
			||||||
 | 
					                                .FirstOrDefault(u => u.ToString().ToLowerInvariant() == x)
 | 
				
			||||||
 | 
					                                ?.Id, 
 | 
				
			||||||
 | 
					                            Reason: reason);
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //if user is null, means that person couldn't be found
 | 
				
			||||||
 | 
					                var missing = bans
 | 
				
			||||||
 | 
					                    .Where(x => !x.Id.HasValue)
 | 
				
			||||||
 | 
					                    .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //get only data for found users
 | 
				
			||||||
 | 
					                var found = bans
 | 
				
			||||||
 | 
					                    .Where(x => x.Id.HasValue)
 | 
				
			||||||
 | 
					                    .Select(x => x.Id.Value)
 | 
				
			||||||
 | 
					                    .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var missStr = string.Join("\n", missing);
 | 
				
			||||||
 | 
					                if (string.IsNullOrWhiteSpace(missStr))
 | 
				
			||||||
 | 
					                    missStr = "-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //send a message but don't wait for it
 | 
				
			||||||
 | 
					                var banningMessageTask = Context.Channel.EmbedAsync(new EmbedBuilder()
 | 
				
			||||||
 | 
					                    .WithDescription(GetText("mass_kill_in_progress", bans.Length))
 | 
				
			||||||
 | 
					                    .AddField(GetText("invalid", missing.Length), missStr)
 | 
				
			||||||
 | 
					                    .WithOkColor());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                using (var uow = _db.UnitOfWork)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var bc = uow.BotConfig.GetOrCreate(set => set.Include(x => x.Blacklist));
 | 
				
			||||||
 | 
					                    //blacklist the users
 | 
				
			||||||
 | 
					                    bc.Blacklist.AddRange(found.Select(x =>
 | 
				
			||||||
 | 
					                        new BlacklistItem
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            ItemId = x,
 | 
				
			||||||
 | 
					                            Type = BlacklistType.User,
 | 
				
			||||||
 | 
					                        }));
 | 
				
			||||||
 | 
					                    //clear their currencies
 | 
				
			||||||
 | 
					                    uow.Currency.RemoveFromMany(found.Select(x => (long)x).ToList());
 | 
				
			||||||
 | 
					                    uow.Complete();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _bc.Reload();
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                //do the banning
 | 
				
			||||||
 | 
					                await Task.WhenAll(bans
 | 
				
			||||||
 | 
					                    .Where(x => x.Id.HasValue)
 | 
				
			||||||
 | 
					                    .Select(x => Context.Guild.AddBanAsync(x.Id.Value, 7, x.Reason, new RequestOptions() {
 | 
				
			||||||
 | 
					                        RetryMode = RetryMode.AlwaysRetry,
 | 
				
			||||||
 | 
					                    })))
 | 
				
			||||||
 | 
					                    .ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //wait for the message and edit it
 | 
				
			||||||
 | 
					                var banningMessage = await banningMessageTask.ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
 | 
				
			||||||
 | 
					                    .WithDescription(GetText("mass_kill_completed", bans.Length))
 | 
				
			||||||
 | 
					                    .AddField(GetText("invalid", missing.Length), missStr)
 | 
				
			||||||
 | 
					                    .WithOkColor()
 | 
				
			||||||
 | 
					                    .Build()).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,6 +107,22 @@ namespace NadekoBot.Modules.Gambling
 | 
				
			|||||||
            await Context.Channel.SendConfirmAsync("🎟 "+ GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
 | 
					            await Context.Channel.SendConfirmAsync("🎟 "+ GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [NadekoCommand, Usage, Description, Aliases]
 | 
				
			||||||
 | 
					        [RequireContext(ContextType.Guild)]
 | 
				
			||||||
 | 
					        public async Task RaffleAny([Remainder] IRole role = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            role = role ?? Context.Guild.EveryoneRole;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var members = (await role.GetMembersAsync());
 | 
				
			||||||
 | 
					            var membersArray = members as IUser[] ?? members.ToArray();
 | 
				
			||||||
 | 
					            if (membersArray.Length == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
 | 
				
			||||||
 | 
					            await Context.Channel.SendConfirmAsync("🎟 " + GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
					        [NadekoCommand, Usage, Description, Aliases]
 | 
				
			||||||
        [Priority(1)]
 | 
					        [Priority(1)]
 | 
				
			||||||
        public async Task Cash([Remainder] IUser user = null)
 | 
					        public async Task Cash([Remainder] IUser user = null)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Searches
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (novelData == null)
 | 
					                if (novelData == null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    await ReplyErrorLocalized("failed_finding_novel").ConfigureAwait(false);
 | 
					                    await ReplyErrorLocalized("error_finding_novel").ConfigureAwait(false);
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,10 +53,28 @@ namespace NadekoBot.Modules.Searches.Services
 | 
				
			|||||||
        private readonly ConcurrentDictionary<ulong, HashSet<string>> _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>();
 | 
					        private readonly ConcurrentDictionary<ulong, HashSet<string>> _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>();
 | 
				
			||||||
        private readonly Timer _t;
 | 
					        private readonly Timer _t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private readonly SemaphoreSlim _cryptoLock = new SemaphoreSlim(1, 1);
 | 
				
			||||||
        public async Task<CryptoData[]> CryptoData()
 | 
					        public async Task<CryptoData[]> CryptoData()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var data = await _cache.Redis.GetDatabase()
 | 
					            string data;
 | 
				
			||||||
                .StringGetAsync("crypto_data").ConfigureAwait(false);
 | 
					            var r = _cache.Redis.GetDatabase();
 | 
				
			||||||
 | 
					            await _cryptoLock.WaitAsync().ConfigureAwait(false);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                data = await r.StringGetAsync("crypto_data").ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (data == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    data = await Http.GetStringAsync("https://api.coinmarketcap.com/v1/ticker/")
 | 
				
			||||||
 | 
					                        .ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    await r.StringSetAsync("crypto_data", data, TimeSpan.FromHours(1)).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _cryptoLock.Release();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return JsonConvert.DeserializeObject<CryptoData[]>(data);
 | 
					            return JsonConvert.DeserializeObject<CryptoData[]>(data);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -121,14 +139,7 @@ namespace NadekoBot.Modules.Searches.Services
 | 
				
			|||||||
                    var r = _cache.Redis.GetDatabase();
 | 
					                    var r = _cache.Redis.GetDatabase();
 | 
				
			||||||
                    try
 | 
					                    try
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        var data = (string)(await r.StringGetAsync("crypto_data").ConfigureAwait(false));
 | 
					                        
 | 
				
			||||||
                        if (data == null)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            data = await Http.GetStringAsync("https://api.coinmarketcap.com/v1/ticker/")
 | 
					 | 
				
			||||||
                                .ConfigureAwait(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            await r.StringSetAsync("crypto_data", data, TimeSpan.FromHours(6)).ConfigureAwait(false);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    catch (Exception ex)
 | 
					                    catch (Exception ex)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,5 +9,6 @@ namespace NadekoBot.Core.Services.Database.Repositories
 | 
				
			|||||||
        long GetUserCurrency(ulong userId);
 | 
					        long GetUserCurrency(ulong userId);
 | 
				
			||||||
        bool TryUpdateState(ulong userId, long change);
 | 
					        bool TryUpdateState(ulong userId, long change);
 | 
				
			||||||
        IEnumerable<Currency> GetTopRichest(int count, int skip);
 | 
					        IEnumerable<Currency> GetTopRichest(int count, int skip);
 | 
				
			||||||
 | 
					        void RemoveFromMany(List<long> ids);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,11 @@ namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
				
			|||||||
        public long GetUserCurrency(ulong userId) => 
 | 
					        public long GetUserCurrency(ulong userId) => 
 | 
				
			||||||
            GetOrCreate(userId).Amount;
 | 
					            GetOrCreate(userId).Amount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void RemoveFromMany(List<long> ids)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _set.RemoveRange(_set.Where(x => ids.Contains((long)x.UserId)));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool TryUpdateState(ulong userId, long change)
 | 
					        public bool TryUpdateState(ulong userId, long change)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var cur = GetOrCreate(userId);
 | 
					            var cur = GetOrCreate(userId);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,14 @@ namespace NadekoBot.Core.Services.Impl
 | 
				
			|||||||
    public class BotConfigProvider : IBotConfigProvider
 | 
					    public class BotConfigProvider : IBotConfigProvider
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly DbService _db;
 | 
					        private readonly DbService _db;
 | 
				
			||||||
 | 
					        private readonly IDataCache _cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public BotConfig BotConfig { get; private set; }
 | 
					        public BotConfig BotConfig { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public BotConfigProvider(DbService db, BotConfig bc)
 | 
					        public BotConfigProvider(DbService db, BotConfig bc, IDataCache cache)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _db = db;
 | 
					            _db = db;
 | 
				
			||||||
 | 
					            _cache = cache;
 | 
				
			||||||
            BotConfig = bc;
 | 
					            BotConfig = bc;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ namespace NadekoBot.Core.Services.Impl
 | 
				
			|||||||
        static Localization()
 | 
					        static Localization()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _commandData = JsonConvert.DeserializeObject<Dictionary<string, CommandData>>(
 | 
					            _commandData = JsonConvert.DeserializeObject<Dictionary<string, CommandData>>(
 | 
				
			||||||
                File.ReadAllText("./data/command_strings.json"));
 | 
					                File.ReadAllText("./_strings/cmd/command_strings.json"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private Localization() { }
 | 
					        private Localization() { }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ namespace NadekoBot.Core.Services.Impl
 | 
				
			|||||||
        private readonly IBotCredentials _creds;
 | 
					        private readonly IBotCredentials _creds;
 | 
				
			||||||
        private readonly DateTime _started;
 | 
					        private readonly DateTime _started;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public const string BotVersion = "2.4.1";
 | 
					        public const string BotVersion = "2.4.3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string Author => "Kwoth#2560";
 | 
					        public string Author => "Kwoth#2560";
 | 
				
			||||||
        public string Library => "Discord.Net";
 | 
					        public string Library => "Discord.Net";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@ namespace NadekoBot
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray();
 | 
					                AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                IBotConfigProvider botConfigProvider = new BotConfigProvider(_db, _botConfig);
 | 
					                IBotConfigProvider botConfigProvider = new BotConfigProvider(_db, _botConfig, Cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                //initialize Services
 | 
					                //initialize Services
 | 
				
			||||||
                Services = new NServiceProvider()
 | 
					                Services = new NServiceProvider()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,43 @@
 | 
				
			|||||||
# NadekoBot a Discord bot 
 | 
					# Setting up NadekoBot on Docker
 | 
				
			||||||
Nadeko is written in C# and Discord.Net for more information visit <https://github.com/Kwoth/NadekoBot>
 | 
					Nadeko is written in C# and Discord.Net for more information visit <https://github.com/Kwoth/NadekoBot>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Install Docker
 | 
					#### Prerequisites
 | 
				
			||||||
Follow the respective guide for your operating system found here [Docker Engine Install Guide](https://docs.docker.com/engine/installation/)
 | 
					- [Docker](https://docs.docker.com/engine/installation/)
 | 
				
			||||||
 | 
					- [Create Discord Bot application](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#creating-discord-bot-application) and [Invite the bot to your server](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/#inviting-your-bot-to-your-server). 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Nadeko Setup Guide
 | 
					#### Setting up the container
 | 
				
			||||||
For this guide we will be using the folder /nadeko as our config root folder.
 | 
					For this guide we will be using the folder /nadeko as our config root folder.
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data uirel/nadeko:1.4
 | 
					docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data uirel/nadeko:1.4
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
-If you are coming from a previous version of nadeko (the old docker) make sure your credentials.json has been copied into this directory and is the only thing in this folder. 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
-If you are making a fresh install, create your credentials.json from the following guide and place it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/)
 | 
					#### Moving `credentials.json` into the docker container. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Next start the docker up with `docker start nadeko; docker logs -f nadeko`
 | 
					- If you are coming from a previous version of nadeko (the old docker) make sure your credentials.json has been copied into this directory and is the only thing in this folder.
 | 
				
			||||||
 | 
					- If you are making a fresh install, create your credentials.json from the following guide and place it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/). 
 | 
				
			||||||
 | 
					- To copy the the file from your computer to a container: 
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					docker cp /Directory/That/Contains/Your/credentials.json nadeko:/credentials.json
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The docker will start and the log file will start scrolling past. Depending on hardware the bot start can take up to 5 minutes on a small DigitalOcean droplet.
 | 
					#### Start up docker
 | 
				
			||||||
Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is ready and can be invited to your server. Ctrl+C at this point to stop viewing the logs.
 | 
					```
 | 
				
			||||||
 | 
					docker start nadeko; docker logs -f nadeko
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					The docker will start and the log file will start scrolling past. This may take a long time. The bot start can take up to 5 minutes on a small DigitalOcean droplet.
 | 
				
			||||||
 | 
					Once the log ends with "NadekoBot | Starting NadekoBot vX.X" the bot is ready and can be invited to your server. Ctrl+C at this point if you would like to stop viewing the logs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
After a few moments you should be able to invite Nadeko to your server. If you cannot, check the log file for errors. 
 | 
					After a few moments, Nadeko should come online on your server. If it doesn't, check the log file for errors. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Monitoring
 | 
					#### Monitoring
 | 
				
			||||||
 | 
					**To monitor the logs of the container in realtime** 
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					docker logs -f nadeko
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Monitor the logs of the container in realtime `docker logs -f nadeko`.
 | 
					### Updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Updates
 | 
					#### Manual
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Manual
 | 
					 | 
				
			||||||
Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko.
 | 
					Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko.
 | 
				
			||||||
The following commands are required for the default options
 | 
					The following commands are required for the default options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,17 +52,17 @@ docker create --name=nadeko -v /nadeko/conf/:/root/nadeko -v /nadeko/data:/opt/N
 | 
				
			|||||||
`docker start nadeko`
 | 
					`docker start nadeko`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Automatic Updates
 | 
					#### Automatic
 | 
				
			||||||
Automatic update are now handled by WatchTower [WatchTower GitHub](https://github.com/CenturyLinkLabs/watchtower)
 | 
					Automatic update are handled by [WatchTower](https://github.com/CenturyLinkLabs/watchtower).
 | 
				
			||||||
To setup WatchTower to keep Nadeko up-to-date for you with the default settings, use the following command
 | 
					To setup WatchTower to keep Nadeko up-to-date for you with the default settings, use the following command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko
 | 
					docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko --interval 300
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the `--interval X` command to change the interval, where X is the amount of time in seconds to wait. e.g 21600 for 6 hours.
 | 
					This will check for updates to the docker every 5 minutes and update immediately. To check in different intervals, change `X`. X is the amount of time, in seconds. (e.g 21600 for 6 hours)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Additional Info
 | 
				
			||||||
If you have any issues with the docker setup, please ask in #help channel on our [Discord server](https://discordapp.com/invite/nadekobot) but indicate you are using the docker.
 | 
					If you have any issues with the docker setup, please ask in #help channel on our [Discord server](https://discordapp.com/invite/nadekobot) but indicate you are using the docker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For information about configuring your bot or its functionality, please check the [documentation](http://nadekobot.readthedocs.io/en/latest).
 | 
					For information about configuring your bot or its functionality, please check the [documentation](http://nadekobot.readthedocs.io/en/latest).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,8 @@ brew install libsodium
 | 
				
			|||||||
brew install tmux
 | 
					brew install tmux
 | 
				
			||||||
brew install python
 | 
					brew install python
 | 
				
			||||||
brew install youtube-dl
 | 
					brew install youtube-dl
 | 
				
			||||||
 | 
					brew install redis
 | 
				
			||||||
 | 
					brew services start redis
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Installing .NET Core SDK
 | 
					#### Installing .NET Core SDK
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@
 | 
				
			|||||||
    <None Update="data\**\*">
 | 
					    <None Update="data\**\*">
 | 
				
			||||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
					      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
				
			||||||
    </None>
 | 
					    </None>
 | 
				
			||||||
    <None Update="_strings\*">
 | 
					    <None Update="_strings\**">
 | 
				
			||||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
					      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
				
			||||||
    </None>
 | 
					    </None>
 | 
				
			||||||
    <None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
 | 
					    <None Update="libsodium.dll;opus.dll;libsodium.so;libopus.so">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -919,5 +919,9 @@
 | 
				
			|||||||
  "searches_crypto_not_found": "Cryptocurrency with that name was not found.",
 | 
					  "searches_crypto_not_found": "Cryptocurrency with that name was not found.",
 | 
				
			||||||
  "searches_did_you_mean": "Did you mean {0}?",
 | 
					  "searches_did_you_mean": "Did you mean {0}?",
 | 
				
			||||||
  "administration_self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.",
 | 
					  "administration_self_assign_level_req": "Self assignable role {0} now requires at least server level {1}.",
 | 
				
			||||||
  "administration_self_assign_not_level": "That self-assignable role requires at least server level {0}."
 | 
					  "administration_self_assign_not_level": "That self-assignable role requires at least server level {0}.",
 | 
				
			||||||
 | 
					  "administration_invalid": "Invalid / Can't be found ({0})",
 | 
				
			||||||
 | 
					  "administration_mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...",
 | 
				
			||||||
 | 
					  "administration_mass_kill_completed": "Mass Banning and Blacklisting of {0} users is complete.",
 | 
				
			||||||
 | 
					  "searches_error_finding_novel": "Can't find that novel. Make sure you've typed the exact full name, and that it exists on novelupdates.com"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -940,12 +940,20 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "raffle": {
 | 
					  "raffle": {
 | 
				
			||||||
    "Cmd": "raffle",
 | 
					    "Cmd": "raffle",
 | 
				
			||||||
    "Desc": "Prints a name and ID of a random user from the online list from the (optional) role.",
 | 
					    "Desc": "Prints a name and ID of a random online user from the server, or from the online user in the specified role.",
 | 
				
			||||||
    "Usage": [
 | 
					    "Usage": [
 | 
				
			||||||
      "{0}raffle",
 | 
					      "{0}raffle",
 | 
				
			||||||
      "{0}raffle RoleName"
 | 
					      "{0}raffle RoleName"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  "raffleany": {
 | 
				
			||||||
 | 
					    "Cmd": "raffleany",
 | 
				
			||||||
 | 
					    "Desc": "Prints a name and ID of a random user from the server, or from the specified role.",
 | 
				
			||||||
 | 
					    "Usage": [
 | 
				
			||||||
 | 
					      "{0}raffleany",
 | 
				
			||||||
 | 
					      "{0}raffleany  RoleName"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "give": {
 | 
					  "give": {
 | 
				
			||||||
    "Cmd": "give",
 | 
					    "Cmd": "give",
 | 
				
			||||||
    "Desc": "Give someone a certain amount of currency.",
 | 
					    "Desc": "Give someone a certain amount of currency.",
 | 
				
			||||||
@@ -3105,5 +3113,12 @@
 | 
				
			|||||||
    "usage": [
 | 
					    "usage": [
 | 
				
			||||||
      "{0}rlr 5 SomeRole"
 | 
					      "{0}rlr 5 SomeRole"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "masskill": {
 | 
				
			||||||
 | 
					    "cmd": "masskill",
 | 
				
			||||||
 | 
					    "desc": "Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away.",
 | 
				
			||||||
 | 
					    "usage": [
 | 
				
			||||||
 | 
					      "{0}masskill BadPerson#1234 Toxic person"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user