Merge remote-tracking branch 'Kwoth/1.9' into 1.9

This commit is contained in:
Shikhir Arora 2017-11-13 17:23:29 -05:00
commit 6b2a1473ec
16 changed files with 205 additions and 47 deletions

View File

@ -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]
@ -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);
}
} }
} }
} }

View File

@ -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)

View File

@ -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;
} }

View File

@ -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)
{ {

View File

@ -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);
} }
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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() { }

View File

@ -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";

View File

@ -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()

View File

@ -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
``` ```
#### Moving `credentials.json` into the docker container.
- 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 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
```
-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/) #### Start up docker
```
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.
Next start the docker up with `docker start nadeko; docker logs -f nadeko` After a few moments, Nadeko should come online on your server. If it doesn't, check the log file for errors.
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. #### Monitoring
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. **To monitor the logs of the container in realtime**
```
docker logs -f nadeko
```
After a few moments you should be able to invite Nadeko to your server. If you cannot, check the log file for errors. ### Updates
## Monitoring #### Manual
* Monitor the logs of the container in realtime `docker logs -f nadeko`.
## Updates
# 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).

View File

@ -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

View File

@ -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">

View File

@ -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"
} }

View File

@ -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"
]
} }
} }