Administration almost done, logcommands left
This commit is contained in:
parent
355425bf80
commit
a4973ffbb3
@ -3,9 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NLog;
|
using NadekoBot.Services.Administration;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -16,31 +14,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class AutoAssignRoleCommands : NadekoSubmodule
|
public class AutoAssignRoleCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//guildid/roleid
|
private readonly DbHandler _db;
|
||||||
private static ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
private readonly AutoAssignRoleService _service;
|
||||||
|
|
||||||
static AutoAssignRoleCommands()
|
public AutoAssignRoleCommands(AutoAssignRoleService service, DbHandler db)
|
||||||
{
|
{
|
||||||
var log = LogManager.GetCurrentClassLogger();
|
_db = db;
|
||||||
|
_service = service;
|
||||||
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
|
|
||||||
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
|
|
||||||
NadekoBot.Client.UserJoined += async (user) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
|
|
||||||
|
|
||||||
if (roleId == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
|
|
||||||
|
|
||||||
if (role != null)
|
|
||||||
await user.AddRoleAsync(role).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { log.Warn(ex); }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -53,18 +33,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
if (role == null)
|
if (role == null)
|
||||||
{
|
{
|
||||||
conf.AutoAssignRoleId = 0;
|
conf.AutoAssignRoleId = 0;
|
||||||
AutoAssignedRoles.TryRemove(Context.Guild.Id, out ulong throwaway);
|
_service.AutoAssignedRoles.TryRemove(Context.Guild.Id, out ulong throwaway);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
conf.AutoAssignRoleId = role.Id;
|
conf.AutoAssignRoleId = role.Id;
|
||||||
AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
|
_service.AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
@ -1,19 +1,9 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.WebSocket;
|
using NadekoBot.Services.Administration;
|
||||||
using NLog;
|
|
||||||
using NadekoBot.Extensions;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
@ -22,64 +12,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class GameChannelCommands : NadekoSubmodule
|
public class GameChannelCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//private static readonly Timer _t;
|
private readonly DbHandler _db;
|
||||||
|
private readonly GameVoiceChannelService _service;
|
||||||
|
|
||||||
private static readonly ConcurrentHashSet<ulong> gameVoiceChannels = new ConcurrentHashSet<ulong>();
|
public GameChannelCommands(GameVoiceChannelService service, DbHandler db)
|
||||||
|
|
||||||
private static new readonly Logger _log;
|
|
||||||
|
|
||||||
static GameChannelCommands()
|
|
||||||
{
|
{
|
||||||
//_t = new Timer(_ => {
|
_db = db;
|
||||||
|
_service = service;
|
||||||
//}, null, );
|
|
||||||
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
gameVoiceChannels = new ConcurrentHashSet<ulong>(
|
|
||||||
NadekoBot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null)
|
|
||||||
.Select(gc => gc.GameVoiceChannel.Value));
|
|
||||||
|
|
||||||
NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task Client_UserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
|
||||||
{
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var gUser = usr as SocketGuildUser;
|
|
||||||
if (gUser == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var game = gUser.Game?.Name.TrimTo(50).ToLowerInvariant();
|
|
||||||
|
|
||||||
if (oldState.VoiceChannel == newState.VoiceChannel ||
|
|
||||||
newState.VoiceChannel == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!gameVoiceChannels.Contains(newState.VoiceChannel.Id) ||
|
|
||||||
string.IsNullOrWhiteSpace(game))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var vch = gUser.Guild.VoiceChannels
|
|
||||||
.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
|
||||||
|
|
||||||
if (vch == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
|
||||||
await gUser.ModifyAsync(gu => gu.Channel = vch).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -96,20 +35,20 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ulong? id;
|
ulong? id;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
|
|
||||||
if (gc.GameVoiceChannel == vch.Id)
|
if (gc.GameVoiceChannel == vch.Id)
|
||||||
{
|
{
|
||||||
gameVoiceChannels.TryRemove(vch.Id);
|
_service.GameVoiceChannels.TryRemove(vch.Id);
|
||||||
id = gc.GameVoiceChannel = null;
|
id = gc.GameVoiceChannel = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(gc.GameVoiceChannel != null)
|
if(gc.GameVoiceChannel != null)
|
||||||
gameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value);
|
_service.GameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value);
|
||||||
gameVoiceChannels.Add(vch.Id);
|
_service.GameVoiceChannels.Add(vch.Id);
|
||||||
id = gc.GameVoiceChannel = vch.Id;
|
id = gc.GameVoiceChannel = vch.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +61,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gameVoiceChannels.Add(vch.Id);
|
_service.GameVoiceChannels.Add(vch.Id);
|
||||||
await ReplyConfirmLocalized("gvc_enabled", Format.Bold(vch.Name)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("gvc_enabled", Format.Bold(vch.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
//Română, România
|
//Română, România
|
||||||
//Bahasa Indonesia, Indonesia
|
//Bahasa Indonesia, Indonesia
|
||||||
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
private static ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
//{"ar", "العربية" },
|
//{"ar", "العربية" },
|
||||||
{"zh-TW", "繁體中文, 台灣" },
|
{"zh-TW", "繁體中文, 台灣" },
|
||||||
@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task LanguageSet()
|
public async Task LanguageSet()
|
||||||
{
|
{
|
||||||
var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild);
|
var cul = _localization.GetCultureInfo(Context.Guild);
|
||||||
await ReplyConfirmLocalized("lang_set_show", Format.Bold(cul.ToString()), Format.Bold(cul.NativeName))
|
await ReplyConfirmLocalized("lang_set_show", Format.Bold(cul.ToString()), Format.Bold(cul.NativeName))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -61,13 +61,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
CultureInfo ci;
|
CultureInfo ci;
|
||||||
if (name.Trim().ToLowerInvariant() == "default")
|
if (name.Trim().ToLowerInvariant() == "default")
|
||||||
{
|
{
|
||||||
NadekoBot.Localization.RemoveGuildCulture(Context.Guild);
|
_localization.RemoveGuildCulture(Context.Guild);
|
||||||
ci = NadekoBot.Localization.DefaultCultureInfo;
|
ci = _localization.DefaultCultureInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ci = new CultureInfo(name);
|
ci = new CultureInfo(name);
|
||||||
NadekoBot.Localization.SetGuildCulture(Context.Guild, ci);
|
_localization.SetGuildCulture(Context.Guild, ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReplyConfirmLocalized("lang_set", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("lang_set", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||||
@ -81,7 +81,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task LanguageSetDefault()
|
public async Task LanguageSetDefault()
|
||||||
{
|
{
|
||||||
var cul = NadekoBot.Localization.DefaultCultureInfo;
|
var cul = _localization.DefaultCultureInfo;
|
||||||
await ReplyConfirmLocalized("lang_set_bot_show", cul, cul.NativeName).ConfigureAwait(false);
|
await ReplyConfirmLocalized("lang_set_bot_show", cul, cul.NativeName).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,13 +94,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
CultureInfo ci;
|
CultureInfo ci;
|
||||||
if (name.Trim().ToLowerInvariant() == "default")
|
if (name.Trim().ToLowerInvariant() == "default")
|
||||||
{
|
{
|
||||||
NadekoBot.Localization.ResetDefaultCulture();
|
_localization.ResetDefaultCulture();
|
||||||
ci = NadekoBot.Localization.DefaultCultureInfo;
|
ci = _localization.DefaultCultureInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ci = new CultureInfo(name);
|
ci = new CultureInfo(name);
|
||||||
NadekoBot.Localization.SetDefaultCulture(ci);
|
_localization.SetDefaultCulture(ci);
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("lang_set_bot", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("lang_set_bot", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
static LogCommands()
|
static LogCommands()
|
||||||
{
|
{
|
||||||
Client = NadekoBot.Client;
|
Client = _client;
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
GuildLogSettings = new ConcurrentDictionary<ulong, LogSetting>(NadekoBot.AllGuildConfigs
|
GuildLogSettings = new ConcurrentDictionary<ulong, LogSetting>(gcs
|
||||||
.ToDictionary(g => g.GuildId, g => g.LogSetting));
|
.ToDictionary(g => g.GuildId, g => g.LogSetting));
|
||||||
|
|
||||||
_timerReference = new Timer(async (state) =>
|
_timerReference = new Timer(async (state) =>
|
||||||
@ -136,7 +136,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
//var guildsMemberOf = NadekoBot.Client.GetGuilds().Where(g => g.Users.Select(u => u.Id).Contains(before.Id)).ToList();
|
//var guildsMemberOf = _client.GetGuilds().Where(g => g.Users.Select(u => u.Id).Contains(before.Id)).ToList();
|
||||||
//foreach (var g in guildsMemberOf)
|
//foreach (var g in guildsMemberOf)
|
||||||
//{
|
//{
|
||||||
// LogSetting logSetting;
|
// LogSetting logSetting;
|
||||||
@ -840,7 +840,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
private static void UnsetLogSetting(ulong guildId, LogType logChannelType)
|
private static void UnsetLogSetting(ulong guildId, LogType logChannelType)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var newLogSetting = uow.GuildConfigs.LogSettingsFor(guildId).LogSetting;
|
var newLogSetting = uow.GuildConfigs.LogSettingsFor(guildId).LogSetting;
|
||||||
switch (logChannelType)
|
switch (logChannelType)
|
||||||
@ -910,7 +910,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
LogSetting logSetting;
|
LogSetting logSetting;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
||||||
GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
||||||
@ -946,7 +946,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
int removed;
|
int removed;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id);
|
var config = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id);
|
||||||
LogSetting logSetting = GuildLogSettings.GetOrAdd(channel.Guild.Id, (id) => config.LogSetting);
|
LogSetting logSetting = GuildLogSettings.GetOrAdd(channel.Guild.Id, (id) => config.LogSetting);
|
||||||
@ -986,7 +986,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
ulong? channelId = null;
|
ulong? channelId = null;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
var logSetting = uow.GuildConfigs.LogSettingsFor(channel.Guild.Id).LogSetting;
|
||||||
GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
GuildLogSettings.AddOrUpdate(channel.Guild.Id, (id) => logSetting, (id, old) => logSetting);
|
||||||
|
@ -8,7 +8,6 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
|
||||||
using NadekoBot.Modules.Administration.Commands.Migration;
|
using NadekoBot.Modules.Administration.Commands.Migration;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
@ -23,12 +22,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public class Migration : NadekoSubmodule
|
public class Migration : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private const int CURRENT_VERSION = 1;
|
private const int CURRENT_VERSION = 1;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
public Migration(DbHandler db)
|
||||||
|
|
||||||
static Migration()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -36,7 +34,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task MigrateData()
|
public async Task MigrateData()
|
||||||
{
|
{
|
||||||
var version = 0;
|
var version = 0;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
version = uow.BotConfig.GetOrCreate().MigrationVersion;
|
version = uow.BotConfig.GetOrCreate().MigrationVersion;
|
||||||
}
|
}
|
||||||
@ -62,7 +60,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
private void Migrate0_9To1_0()
|
private void Migrate0_9To1_0()
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var botConfig = uow.BotConfig.GetOrCreate();
|
var botConfig = uow.BotConfig.GetOrCreate();
|
||||||
MigrateConfig0_9(uow, botConfig);
|
MigrateConfig0_9(uow, botConfig);
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
@ -18,101 +13,31 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class PlayingRotateCommands : NadekoSubmodule
|
public class PlayingRotateCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<PlayingStatus> RotatingStatusMessages { get; }
|
private static readonly object _locker = new object();
|
||||||
public static volatile bool RotatingStatuses;
|
private readonly DbHandler _db;
|
||||||
private readonly object _locker = new object();
|
private readonly PlayingRotateService _service;
|
||||||
private new static Logger _log { get; }
|
|
||||||
private static readonly Timer _t;
|
|
||||||
|
|
||||||
private class TimerState
|
public PlayingRotateCommands(PlayingRotateService service, DbHandler db)
|
||||||
{
|
{
|
||||||
public int Index { get; set; }
|
_db = db;
|
||||||
|
_service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PlayingRotateCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages;
|
|
||||||
RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses;
|
|
||||||
|
|
||||||
_t = new Timer(async (objState) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var state = (TimerState)objState;
|
|
||||||
if (!RotatingStatuses)
|
|
||||||
return;
|
|
||||||
if (state.Index >= RotatingStatusMessages.Count)
|
|
||||||
state.Index = 0;
|
|
||||||
|
|
||||||
if (!RotatingStatusMessages.Any())
|
|
||||||
return;
|
|
||||||
var status = RotatingStatusMessages[state.Index++].Status;
|
|
||||||
if (string.IsNullOrWhiteSpace(status))
|
|
||||||
return;
|
|
||||||
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value()));
|
|
||||||
var shards = NadekoBot.Client.Shards;
|
|
||||||
for (int i = 0; i < shards.Count; i++)
|
|
||||||
{
|
|
||||||
var curShard = shards.ElementAt(i);
|
|
||||||
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard)));
|
|
||||||
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn("Rotating playing status errored.\n" + ex);
|
|
||||||
}
|
|
||||||
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
|
|
||||||
new Dictionary<string, Func<string>> {
|
|
||||||
{ "%servers%", () => NadekoBot.Client.Guilds.Count.ToString()},
|
|
||||||
{ "%users%", () => NadekoBot.Client.Guilds.Sum(s => s.Users.Count).ToString()},
|
|
||||||
{ "%playing%", () => {
|
|
||||||
var cnt = NadekoBot.MusicService.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
|
||||||
if (cnt != 1) return cnt.ToString();
|
|
||||||
try {
|
|
||||||
var mp = NadekoBot.MusicService.MusicPlayers.FirstOrDefault();
|
|
||||||
return mp.Value.CurrentSong.SongInfo.Title;
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return "No songs";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ "%queued%", () => NadekoBot.MusicService.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
|
|
||||||
{ "%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
|
|
||||||
{ "%shardcount%", () => NadekoBot.Client.Shards.Count.ToString() },
|
|
||||||
};
|
|
||||||
|
|
||||||
public static Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =
|
|
||||||
new Dictionary<string, Func<DiscordSocketClient, string>> {
|
|
||||||
{ "%shardid%", (client) => client.ShardId.ToString()},
|
|
||||||
{ "%shardguilds%", (client) => client.Guilds.Count.ToString()},
|
|
||||||
};
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task RotatePlaying()
|
public async Task RotatePlaying()
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
|
|
||||||
RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses;
|
_service.RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses;
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RotatingStatuses)
|
if (_service.RotatingStatuses)
|
||||||
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
||||||
@ -122,12 +47,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task AddPlaying([Remainder] string status)
|
public async Task AddPlaying([Remainder] string status)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
var toAdd = new PlayingStatus { Status = status };
|
var toAdd = new PlayingStatus { Status = status };
|
||||||
config.RotatingStatusMessages.Add(toAdd);
|
config.RotatingStatusMessages.Add(toAdd);
|
||||||
RotatingStatusMessages.Add(toAdd);
|
_service.RotatingStatusMessages.Add(toAdd);
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,13 +63,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task ListPlaying()
|
public async Task ListPlaying()
|
||||||
{
|
{
|
||||||
if (!RotatingStatusMessages.Any())
|
if (!_service.RotatingStatusMessages.Any())
|
||||||
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var i = 1;
|
var i = 1;
|
||||||
await ReplyConfirmLocalized("ropl_list",
|
await ReplyConfirmLocalized("ropl_list",
|
||||||
string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
string.Join("\n\t", _service.RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +82,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
index -= 1;
|
index -= 1;
|
||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.BotConfig.GetOrCreate();
|
var config = uow.BotConfig.GetOrCreate();
|
||||||
|
|
||||||
@ -165,7 +90,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
msg = config.RotatingStatusMessages[index].Status;
|
msg = config.RotatingStatusMessages[index].Status;
|
||||||
config.RotatingStatusMessages.RemoveAt(index);
|
config.RotatingStatusMessages.RemoveAt(index);
|
||||||
RotatingStatusMessages.RemoveAt(index);
|
_service.RotatingStatusMessages.RemoveAt(index);
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
||||||
|
@ -5,246 +5,27 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using NadekoBot.Services.Administration;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
public partial class Administration
|
public partial class Administration
|
||||||
{
|
{
|
||||||
public enum ProtectionType
|
|
||||||
{
|
|
||||||
Raiding,
|
|
||||||
Spamming,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AntiRaidStats
|
|
||||||
{
|
|
||||||
public AntiRaidSetting AntiRaidSettings { get; set; }
|
|
||||||
public int UsersCount { get; set; }
|
|
||||||
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AntiSpamStats
|
|
||||||
{
|
|
||||||
public AntiSpamSetting AntiSpamSettings { get; set; }
|
|
||||||
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
|
||||||
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UserSpamStats : IDisposable
|
|
||||||
{
|
|
||||||
public int Count => timers.Count;
|
|
||||||
public string LastMessage { get; set; }
|
|
||||||
|
|
||||||
private ConcurrentQueue<Timer> timers { get; }
|
|
||||||
|
|
||||||
public UserSpamStats(IUserMessage msg)
|
|
||||||
{
|
|
||||||
LastMessage = msg.Content.ToUpperInvariant();
|
|
||||||
timers = new ConcurrentQueue<Timer>();
|
|
||||||
|
|
||||||
ApplyNextMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object applyLock = new object();
|
|
||||||
public void ApplyNextMessage(IUserMessage message)
|
|
||||||
{
|
|
||||||
lock(applyLock){
|
|
||||||
var upperMsg = message.Content.ToUpperInvariant();
|
|
||||||
if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any()))
|
|
||||||
{
|
|
||||||
LastMessage = upperMsg;
|
|
||||||
//todo c#7
|
|
||||||
Timer old;
|
|
||||||
while(timers.TryDequeue(out old))
|
|
||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
}
|
|
||||||
var t = new Timer((_) => {
|
|
||||||
//todo c#7
|
|
||||||
Timer __;
|
|
||||||
if(timers.TryDequeue(out __))
|
|
||||||
__.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
}, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30));
|
|
||||||
timers.Enqueue(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
//todo c#7
|
|
||||||
Timer old;
|
|
||||||
while(timers.TryDequeue(out old))
|
|
||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class ProtectionCommands : NadekoSubmodule
|
public class ProtectionCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<ulong, AntiRaidStats> _antiRaidGuilds =
|
private readonly ProtectionService _service;
|
||||||
new ConcurrentDictionary<ulong, AntiRaidStats>();
|
private readonly MuteService _mute;
|
||||||
// guildId | (userId|messages)
|
private readonly DbHandler _db;
|
||||||
private static readonly ConcurrentDictionary<ulong, AntiSpamStats> _antiSpamGuilds =
|
|
||||||
new ConcurrentDictionary<ulong, AntiSpamStats>();
|
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
public ProtectionCommands(ProtectionService service, MuteService mute, DbHandler db)
|
||||||
|
|
||||||
static ProtectionCommands()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_service = service;
|
||||||
|
_mute = mute;
|
||||||
foreach (var gc in NadekoBot.AllGuildConfigs)
|
_db = db;
|
||||||
{
|
|
||||||
var raid = gc.AntiRaidSetting;
|
|
||||||
var spam = gc.AntiSpamSetting;
|
|
||||||
|
|
||||||
if (raid != null)
|
|
||||||
{
|
|
||||||
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
|
||||||
_antiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spam != null)
|
|
||||||
_antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
|
||||||
}
|
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += (imsg) =>
|
|
||||||
{
|
|
||||||
var msg = imsg as IUserMessage;
|
|
||||||
if (msg == null || msg.Author.IsBot)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var channel = msg.Channel as ITextChannel;
|
|
||||||
if (channel == null)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AntiSpamStats spamSettings;
|
|
||||||
if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
|
||||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
|
||||||
{
|
|
||||||
ChannelId = channel.Id
|
|
||||||
}))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, (id) => new UserSpamStats(msg),
|
|
||||||
(id, old) =>
|
|
||||||
{
|
|
||||||
old.ApplyNextMessage(msg); return old;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
|
||||||
{
|
|
||||||
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
|
||||||
{
|
|
||||||
stats.Dispose();
|
|
||||||
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
NadekoBot.Client.UserJoined += (usr) =>
|
|
||||||
{
|
|
||||||
if (usr.IsBot)
|
|
||||||
return Task.CompletedTask;
|
|
||||||
AntiRaidStats settings;
|
|
||||||
if (!_antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
if (!settings.RaidUsers.Add(usr))
|
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
++settings.UsersCount;
|
|
||||||
|
|
||||||
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
|
||||||
{
|
|
||||||
var users = settings.RaidUsers.ToArray();
|
|
||||||
settings.RaidUsers.Clear();
|
|
||||||
|
|
||||||
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false);
|
|
||||||
|
|
||||||
settings.RaidUsers.TryRemove(usr);
|
|
||||||
--settings.UsersCount;
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
|
||||||
{
|
|
||||||
_log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild");
|
|
||||||
foreach (var gu in gus)
|
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case PunishmentAction.Mute:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await MuteCommands.MuteUser(gu).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
|
||||||
break;
|
|
||||||
case PunishmentAction.Kick:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await gu.KickAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
|
||||||
break;
|
|
||||||
case PunishmentAction.Softban:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
|
||||||
// try it twice, really don't want to ban user if
|
|
||||||
// only kick has been specified as the punishement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
|
||||||
break;
|
|
||||||
case PunishmentAction.Ban:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAntiSpamString(AntiSpamStats stats)
|
private string GetAntiSpamString(AntiSpamStats stats)
|
||||||
@ -282,9 +63,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
|
|
||||||
AntiRaidStats throwaway;
|
AntiRaidStats throwaway;
|
||||||
if (_antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
if (_service.AntiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||||
|
|
||||||
@ -297,7 +78,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
await _mute.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -316,9 +97,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
_service.AntiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting));
|
||||||
|
|
||||||
@ -339,10 +120,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
AntiSpamStats throwaway;
|
AntiSpamStats throwaway;
|
||||||
if (_antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
if (_service.AntiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||||
{
|
{
|
||||||
throwaway.UserStats.ForEach(x => x.Value.Dispose());
|
throwaway.UserStats.ForEach(x => x.Value.Dispose());
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)
|
||||||
.ThenInclude(x => x.IgnoredChannels));
|
.ThenInclude(x => x.IgnoredChannels));
|
||||||
@ -356,7 +137,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
await _mute.GetMuteRole(Context.Guild).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -374,9 +155,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
_service.AntiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting));
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting));
|
||||||
|
|
||||||
@ -398,7 +179,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
ChannelId = channel.Id
|
ChannelId = channel.Id
|
||||||
};
|
};
|
||||||
bool added;
|
bool added;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels));
|
||||||
var spam = gc.AntiSpamSetting;
|
var spam = gc.AntiSpamSetting;
|
||||||
@ -410,7 +191,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (spam.IgnoredChannels.Add(obj))
|
if (spam.IgnoredChannels.Add(obj))
|
||||||
{
|
{
|
||||||
AntiSpamStats temp;
|
AntiSpamStats temp;
|
||||||
if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
if (_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||||
temp.AntiSpamSettings.IgnoredChannels.Add(obj);
|
temp.AntiSpamSettings.IgnoredChannels.Add(obj);
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
@ -418,7 +199,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
spam.IgnoredChannels.Remove(obj);
|
spam.IgnoredChannels.Remove(obj);
|
||||||
AntiSpamStats temp;
|
AntiSpamStats temp;
|
||||||
if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
if (_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||||
temp.AntiSpamSettings.IgnoredChannels.Remove(obj);
|
temp.AntiSpamSettings.IgnoredChannels.Remove(obj);
|
||||||
added = false;
|
added = false;
|
||||||
}
|
}
|
||||||
@ -437,10 +218,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task AntiList()
|
public async Task AntiList()
|
||||||
{
|
{
|
||||||
AntiSpamStats spam;
|
AntiSpamStats spam;
|
||||||
_antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
_service.AntiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
||||||
|
|
||||||
AntiRaidStats raid;
|
AntiRaidStats raid;
|
||||||
_antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
_service.AntiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
||||||
|
|
||||||
if (spam == null && raid == null)
|
if (spam == null && raid == null)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Administration;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
@ -21,85 +22,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class RatelimitCommands : NadekoSubmodule
|
public class RatelimitCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
private readonly RatelimitService _service;
|
||||||
public static ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
private readonly DbHandler _db;
|
||||||
public static ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
public RatelimitCommands(RatelimitService service, DbHandler db)
|
||||||
|
|
||||||
public class Ratelimiter
|
|
||||||
{
|
{
|
||||||
public class RatelimitedUser
|
_service = service;
|
||||||
{
|
_db = db;
|
||||||
public ulong UserId { get; set; }
|
|
||||||
public int MessageCount { get; set; } = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong ChannelId { get; set; }
|
|
||||||
|
|
||||||
public int MaxMessages { get; set; }
|
|
||||||
public int PerSeconds { get; set; }
|
|
||||||
|
|
||||||
public CancellationTokenSource CancelSource { get; set; } = new CancellationTokenSource();
|
|
||||||
|
|
||||||
public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
|
|
||||||
|
|
||||||
public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser)
|
|
||||||
{
|
|
||||||
if ((IgnoredUsers.TryGetValue(guildId, out HashSet<ulong> ignoreUsers) && ignoreUsers.Contains(id)) ||
|
|
||||||
(optUser != null && IgnoredRoles.TryGetValue(guildId, out HashSet<ulong> ignoreRoles) && optUser.Roles.Any(x => ignoreRoles.Contains(x.Id))))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
|
||||||
if (usr.MessageCount >= MaxMessages)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
usr.MessageCount++;
|
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await Task.Delay(PerSeconds * 1000, CancelSource.Token);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException) { }
|
|
||||||
usr.MessageCount--;
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static RatelimitCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
|
||||||
NadekoBot.AllGuildConfigs
|
|
||||||
.ToDictionary(x => x.GuildId,
|
|
||||||
x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId))));
|
|
||||||
|
|
||||||
IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
|
||||||
NadekoBot.AllGuildConfigs
|
|
||||||
.ToDictionary(x => x.GuildId,
|
|
||||||
x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId))));
|
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += async (umsg) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var usrMsg = umsg as SocketUserMessage;
|
|
||||||
var channel = usrMsg?.Channel as SocketTextChannel;
|
|
||||||
|
|
||||||
if (channel == null || usrMsg.IsAuthor())
|
|
||||||
return;
|
|
||||||
if (!RatelimitingChannels.TryGetValue(channel.Id, out Ratelimiter limiter))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser))
|
|
||||||
await usrMsg.DeleteAsync();
|
|
||||||
}
|
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -107,7 +36,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task Slowmode()
|
public async Task Slowmode()
|
||||||
{
|
{
|
||||||
if (RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter throwaway))
|
if (_service.RatelimitingChannels.TryRemove(Context.Channel.Id, out Ratelimiter throwaway))
|
||||||
{
|
{
|
||||||
throwaway.CancelSource.Cancel();
|
throwaway.CancelSource.Cancel();
|
||||||
await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
|
await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
|
||||||
@ -126,13 +55,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await ReplyErrorLocalized("invalid_params").ConfigureAwait(false);
|
await ReplyErrorLocalized("invalid_params").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var toAdd = new Ratelimiter()
|
var toAdd = new Ratelimiter(_service)
|
||||||
{
|
{
|
||||||
ChannelId = Context.Channel.Id,
|
ChannelId = Context.Channel.Id,
|
||||||
MaxMessages = msg,
|
MaxMessages = msg,
|
||||||
PerSeconds = perSec,
|
PerSeconds = perSec,
|
||||||
};
|
};
|
||||||
if(RatelimitingChannels.TryAdd(Context.Channel.Id, toAdd))
|
if(_service.RatelimitingChannels.TryAdd(Context.Channel.Id, toAdd))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(GetText("slowmode_init"),
|
await Context.Channel.SendConfirmAsync(GetText("slowmode_init"),
|
||||||
GetText("slowmode_desc", Format.Bold(toAdd.MaxMessages.ToString()), Format.Bold(toAdd.PerSeconds.ToString())))
|
GetText("slowmode_desc", Format.Bold(toAdd.MaxMessages.ToString()), Format.Bold(toAdd.PerSeconds.ToString())))
|
||||||
@ -153,7 +82,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
HashSet<SlowmodeIgnoredUser> usrs;
|
HashSet<SlowmodeIgnoredUser> usrs;
|
||||||
bool removed;
|
bool removed;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers))
|
usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers))
|
||||||
.SlowmodeIgnoredUsers;
|
.SlowmodeIgnoredUsers;
|
||||||
@ -164,7 +93,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(usrs.Select(x => x.UserId)), (key, old) => new HashSet<ulong>(usrs.Select(x => x.UserId)));
|
_service.IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(usrs.Select(x => x.UserId)), (key, old) => new HashSet<ulong>(usrs.Select(x => x.UserId)));
|
||||||
|
|
||||||
if(removed)
|
if(removed)
|
||||||
await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
@ -185,7 +114,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
HashSet<SlowmodeIgnoredRole> roles;
|
HashSet<SlowmodeIgnoredRole> roles;
|
||||||
bool removed;
|
bool removed;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles))
|
roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles))
|
||||||
.SlowmodeIgnoredRoles;
|
.SlowmodeIgnoredRoles;
|
||||||
@ -196,7 +125,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(roles.Select(x => x.RoleId)), (key, old) => new HashSet<ulong>(roles.Select(x => x.RoleId)));
|
_service.IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(roles.Select(x => x.RoleId)), (key, old) => new HashSet<ulong>(roles.Select(x => x.RoleId)));
|
||||||
|
|
||||||
if (removed)
|
if (removed)
|
||||||
await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false);
|
||||||
|
@ -18,6 +18,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class SelfAssignedRolesCommands : NadekoSubmodule
|
public class SelfAssignedRolesCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
|
||||||
|
public SelfAssignedRolesCommands(DbHandler db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -25,7 +31,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task AdSarm()
|
public async Task AdSarm()
|
||||||
{
|
{
|
||||||
bool newval;
|
bool newval;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
|
newval = config.AutoDeleteSelfAssignedRoleMessages = !config.AutoDeleteSelfAssignedRoleMessages;
|
||||||
@ -49,7 +55,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
var error = false;
|
var error = false;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
||||||
@ -84,7 +90,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
success = uow.SelfAssignedRoles.DeleteByGuildAndRoleId(role.Guild.Id, role.Id);
|
success = uow.SelfAssignedRoles.DeleteByGuildAndRoleId(role.Guild.Id, role.Id);
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
@ -105,7 +111,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var removeMsg = new StringBuilder();
|
var removeMsg = new StringBuilder();
|
||||||
var msg = new StringBuilder();
|
var msg = new StringBuilder();
|
||||||
var roleCnt = 0;
|
var roleCnt = 0;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var roleModels = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToList();
|
var roleModels = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToList();
|
||||||
msg.AppendLine();
|
msg.AppendLine();
|
||||||
@ -139,7 +145,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public async Task Tesar()
|
public async Task Tesar()
|
||||||
{
|
{
|
||||||
bool areExclusive;
|
bool areExclusive;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
|
|
||||||
@ -160,7 +166,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
GuildConfig conf;
|
GuildConfig conf;
|
||||||
SelfAssignedRole[] roles;
|
SelfAssignedRole[] roles;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToArray();
|
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToArray();
|
||||||
@ -220,7 +226,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
bool autoDeleteSelfAssignedRoleMessages;
|
bool autoDeleteSelfAssignedRoleMessages;
|
||||||
IEnumerable<SelfAssignedRole> roles;
|
IEnumerable<SelfAssignedRole> roles;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(Context.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages;
|
autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(Context.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages;
|
||||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||||
|
@ -25,7 +25,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public UserPunishCommands(DbHandler db, MuteService muteService)
|
public UserPunishCommands(DbHandler db, MuteService muteService)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
|
|
||||||
_muteService = muteService;
|
_muteService = muteService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,38 +7,26 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord;
|
using Discord;
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json;
|
using NadekoBot.Services.Pokemon;
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Pokemon
|
namespace NadekoBot.Modules.Pokemon
|
||||||
{
|
{
|
||||||
[NadekoModule("Pokemon", ">")]
|
|
||||||
public class Pokemon : NadekoTopLevelModule
|
public class Pokemon : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
private readonly PokemonService _service;
|
||||||
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
private readonly DbHandler _db;
|
||||||
|
private readonly BotConfig _bc;
|
||||||
|
private readonly CurrencyHandler _ch;
|
||||||
|
|
||||||
public const string PokemonTypesFile = "data/pokemon_types.json";
|
public Pokemon(PokemonService pokemonService, DbHandler db, BotConfig bc, CurrencyHandler ch)
|
||||||
|
|
||||||
private new static Logger _log { get; }
|
|
||||||
|
|
||||||
static Pokemon()
|
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_service = pokemonService;
|
||||||
if (File.Exists(PokemonTypesFile))
|
_db = db;
|
||||||
{
|
_bc = bc;
|
||||||
_pokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
|
_ch = ch;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_log.Warn(PokemonTypesFile + " is missing. Pokemon types not loaded.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private int GetDamage(PokemonType usertype, PokemonType targetType)
|
private int GetDamage(PokemonType usertype, PokemonType targetType)
|
||||||
{
|
{
|
||||||
var rng = new Random();
|
var rng = new Random();
|
||||||
@ -52,12 +40,11 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PokemonType GetPokeType(ulong id)
|
||||||
private static PokemonType GetPokeType(ulong id)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Dictionary<ulong, string> setTypes;
|
Dictionary<ulong, string> setTypes;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
setTypes = uow.PokeGame.GetAll().ToDictionary(x => x.UserId, y => y.type);
|
setTypes = uow.PokeGame.GetAll().ToDictionary(x => x.UserId, y => y.type);
|
||||||
}
|
}
|
||||||
@ -66,17 +53,17 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
{
|
{
|
||||||
return StringToPokemonType(setTypes[id]);
|
return StringToPokemonType(setTypes[id]);
|
||||||
}
|
}
|
||||||
var count = _pokemonTypes.Count;
|
var count = _service.PokemonTypes.Count;
|
||||||
|
|
||||||
var remainder = Math.Abs((int)(id % (ulong)count));
|
var remainder = Math.Abs((int)(id % (ulong)count));
|
||||||
|
|
||||||
return _pokemonTypes[remainder];
|
return _service.PokemonTypes[remainder];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PokemonType StringToPokemonType(string v)
|
private PokemonType StringToPokemonType(string v)
|
||||||
{
|
{
|
||||||
var str = v?.ToUpperInvariant();
|
var str = v?.ToUpperInvariant();
|
||||||
var list = _pokemonTypes;
|
var list = _service.PokemonTypes;
|
||||||
foreach (var p in list)
|
foreach (var p in list)
|
||||||
{
|
{
|
||||||
if (str == p.Name)
|
if (str == p.Name)
|
||||||
@ -111,7 +98,7 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
|
|
||||||
// Checking stats first, then move
|
// Checking stats first, then move
|
||||||
//Set up the userstats
|
//Set up the userstats
|
||||||
var userStats = _stats.GetOrAdd(user.Id, new PokeStats());
|
var userStats = _service.Stats.GetOrAdd(user.Id, new PokeStats());
|
||||||
|
|
||||||
//Check if able to move
|
//Check if able to move
|
||||||
//User not able if HP < 0, has made more than 4 attacks
|
//User not able if HP < 0, has made more than 4 attacks
|
||||||
@ -131,7 +118,7 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//get target stats
|
//get target stats
|
||||||
var targetStats = _stats.GetOrAdd(targetUser.Id, new PokeStats());
|
var targetStats = _service.Stats.GetOrAdd(targetUser.Id, new PokeStats());
|
||||||
|
|
||||||
//If target's HP is below 0, no use attacking
|
//If target's HP is below 0, no use attacking
|
||||||
if (targetStats.Hp <= 0)
|
if (targetStats.Hp <= 0)
|
||||||
@ -195,8 +182,8 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
|
|
||||||
//update dictionary
|
//update dictionary
|
||||||
//This can stay the same right?
|
//This can stay the same right?
|
||||||
_stats[user.Id] = userStats;
|
_service.Stats[user.Id] = userStats;
|
||||||
_stats[targetUser.Id] = targetStats;
|
_service.Stats[targetUser.Id] = targetStats;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -228,9 +215,9 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_stats.ContainsKey(targetUser.Id))
|
if (_service.Stats.ContainsKey(targetUser.Id))
|
||||||
{
|
{
|
||||||
var targetStats = _stats[targetUser.Id];
|
var targetStats = _service.Stats[targetUser.Id];
|
||||||
if (targetStats.Hp == targetStats.MaxHp)
|
if (targetStats.Hp == targetStats.MaxHp)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false);
|
await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false);
|
||||||
@ -242,9 +229,9 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
var target = (targetUser.Id == user.Id) ? "yourself" : targetUser.Mention;
|
var target = (targetUser.Id == user.Id) ? "yourself" : targetUser.Mention;
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
{
|
{
|
||||||
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
|
if (!await _ch.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyErrorLocalized("no_currency", _bc.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,16 +241,16 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
if (targetStats.Hp < 0)
|
if (targetStats.Hp < 0)
|
||||||
{
|
{
|
||||||
//Could heal only for half HP?
|
//Could heal only for half HP?
|
||||||
_stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
|
_service.Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
|
||||||
if (target == "yourself")
|
if (target == "yourself")
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyConfirmLocalized("revive_yourself", _bc.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), _bc.CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), _bc.CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -291,7 +278,7 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
var targetType = StringToPokemonType(typeTargeted);
|
var targetType = StringToPokemonType(typeTargeted);
|
||||||
if (targetType == null)
|
if (targetType == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.EmbedAsync(_pokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
|
await Context.Channel.EmbedAsync(_service.PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
|
||||||
(eb, pt) => eb.AddField(efb => efb.WithName(pt.Name)
|
(eb, pt) => eb.AddField(efb => efb.WithName(pt.Name)
|
||||||
.WithValue(pt.Icon)
|
.WithValue(pt.Icon)
|
||||||
.WithIsInline(true)))
|
.WithIsInline(true)))
|
||||||
@ -308,16 +295,16 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
var amount = 1;
|
var amount = 1;
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
{
|
{
|
||||||
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
|
if (!await _ch.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
await ReplyErrorLocalized("no_currency", _bc.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Actually changing the type here
|
//Actually changing the type here
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = _db.UnitOfWork)
|
||||||
{
|
{
|
||||||
var pokeUsers = uow.PokeGame.GetAll().ToArray();
|
var pokeUsers = uow.PokeGame.GetAll().ToArray();
|
||||||
var setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
|
var setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
|
||||||
@ -344,7 +331,7 @@ namespace NadekoBot.Modules.Pokemon
|
|||||||
//Now for the response
|
//Now for the response
|
||||||
await ReplyConfirmLocalized("settype_success",
|
await ReplyConfirmLocalized("settype_success",
|
||||||
targetType,
|
targetType,
|
||||||
NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
_bc.CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -97,8 +97,12 @@ namespace NadekoBot
|
|||||||
var soundcloud = new SoundCloudApiService(credentials);
|
var soundcloud = new SoundCloudApiService(credentials);
|
||||||
|
|
||||||
//module services
|
//module services
|
||||||
|
//todo 90 - Make this automatic
|
||||||
var utilityService = new UtilityService(AllGuildConfigs, Client, BotConfig, db);
|
var utilityService = new UtilityService(AllGuildConfigs, Client, BotConfig, db);
|
||||||
|
#region Searches
|
||||||
var searchesService = new SearchesService(Client, google, db);
|
var searchesService = new SearchesService(Client, google, db);
|
||||||
|
var streamNotificationService = new StreamNotificationService(db, Client, strings);
|
||||||
|
#endregion
|
||||||
var clashService = new ClashOfClansService(Client, db, localization, strings);
|
var clashService = new ClashOfClansService(Client, db, localization, strings);
|
||||||
var musicService = new MusicService(google, strings, localization, db, soundcloud, credentials);
|
var musicService = new MusicService(google, strings, localization, db, soundcloud, credentials);
|
||||||
var crService = new CustomReactionsService(db, Client);
|
var crService = new CustomReactionsService(db, Client);
|
||||||
@ -108,11 +112,16 @@ namespace NadekoBot
|
|||||||
var selfService = new SelfService(this, commandHandler, db, BotConfig);
|
var selfService = new SelfService(this, commandHandler, db, BotConfig);
|
||||||
var vcRoleService = new VcRoleService(Client, AllGuildConfigs);
|
var vcRoleService = new VcRoleService(Client, AllGuildConfigs);
|
||||||
var vPlusTService = new VplusTService(Client, AllGuildConfigs, strings, db);
|
var vPlusTService = new VplusTService(Client, AllGuildConfigs, strings, db);
|
||||||
|
var muteService = new MuteService(Client, AllGuildConfigs, db);
|
||||||
|
var ratelimitService = new RatelimitService(Client, AllGuildConfigs);
|
||||||
|
var protectionService = new ProtectionService(Client, AllGuildConfigs, muteService);
|
||||||
|
var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService);
|
||||||
|
var gameVcService = new GameVoiceChannelService(Client, db, AllGuildConfigs);
|
||||||
|
var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
//initialize Services
|
//initialize Services
|
||||||
Services = new NServiceProvider.ServiceProviderBuilder() //todo all Adds should be interfaces
|
Services = new NServiceProvider.ServiceProviderBuilder()
|
||||||
.Add<ILocalization>(localization)
|
.Add<ILocalization>(localization)
|
||||||
.Add<IStatsService>(stats)
|
.Add<IStatsService>(stats)
|
||||||
.Add<IImagesService>(images)
|
.Add<IImagesService>(images)
|
||||||
@ -129,14 +138,22 @@ namespace NadekoBot
|
|||||||
//modules
|
//modules
|
||||||
.Add<UtilityService>(utilityService)
|
.Add<UtilityService>(utilityService)
|
||||||
.Add<SearchesService>(searchesService)
|
.Add<SearchesService>(searchesService)
|
||||||
|
.Add(streamNotificationService)
|
||||||
.Add<ClashOfClansService>(clashService)
|
.Add<ClashOfClansService>(clashService)
|
||||||
.Add<MusicService>(musicService)
|
.Add<MusicService>(musicService)
|
||||||
.Add<GreetSettingsService>(greetSettingsService)
|
.Add<GreetSettingsService>(greetSettingsService)
|
||||||
.Add<CustomReactionsService>(crService)
|
.Add<CustomReactionsService>(crService)
|
||||||
.Add<GamesService>(gamesService)
|
.Add<GamesService>(gamesService)
|
||||||
.Add(selfService)
|
.Add<AdministrationService>(administrationService)
|
||||||
.Add(vcRoleService)
|
.Add(selfService)
|
||||||
.Add(vPlusTService)
|
.Add(vcRoleService)
|
||||||
|
.Add(vPlusTService)
|
||||||
|
.Add(muteService)
|
||||||
|
.Add(ratelimitService)
|
||||||
|
.Add(playingRotateService)
|
||||||
|
.Add(gameVcService)
|
||||||
|
.Add(autoAssignRoleService)
|
||||||
|
.Add(protectionService)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
commandHandler.AddServices(Services);
|
commandHandler.AddServices(Services);
|
||||||
|
@ -39,7 +39,17 @@
|
|||||||
<None Remove="Modules\Permissions\**" />
|
<None Remove="Modules\Permissions\**" />
|
||||||
<Compile Remove="Modules\Gambling\Commands\Lucky7Commands.cs" />
|
<Compile Remove="Modules\Gambling\Commands\Lucky7Commands.cs" />
|
||||||
<Compile Include="Modules\Administration\Administration.cs" />
|
<Compile Include="Modules\Administration\Administration.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\AutoAssignRoleCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\GameChannelCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\LocalizationCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\Migration.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\Migration\0_9..cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\Migration\MigrationException.cs" />
|
||||||
<Compile Include="Modules\Administration\Commands\MuteCommands.cs" />
|
<Compile Include="Modules\Administration\Commands\MuteCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\PlayingRotateCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\ProtectionCommands.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
|
||||||
|
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
|
||||||
<Compile Include="Modules\Administration\Commands\SelfCommands.cs" />
|
<Compile Include="Modules\Administration\Commands\SelfCommands.cs" />
|
||||||
<Compile Include="Modules\Administration\Commands\ServerGreetCommands.cs" />
|
<Compile Include="Modules\Administration\Commands\ServerGreetCommands.cs" />
|
||||||
<Compile Include="Modules\Administration\Commands\UserPunishCommands.cs" />
|
<Compile Include="Modules\Administration\Commands\UserPunishCommands.cs" />
|
||||||
@ -61,7 +71,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
<PackageReference Include="AngleSharp" Version="0.9.9" />
|
||||||
<PackageReference Include="Discord.Net" Version="1.0.0-rc3-00743" />
|
<PackageReference Include="Discord.Net" Version="1.0.0-rc3-00746" />
|
||||||
<PackageReference Include="libvideo" Version="1.0.1" />
|
<PackageReference Include="libvideo" Version="1.0.1" />
|
||||||
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
<PackageReference Include="CoreCLR-NCalc" Version="2.1.2" />
|
||||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.19.0.138" />
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class AutoAssignRoleService
|
||||||
|
{
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
//guildid/roleid
|
||||||
|
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
||||||
|
|
||||||
|
public AutoAssignRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(
|
||||||
|
gcs.Where(x => x.AutoAssignRoleId != 0)
|
||||||
|
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
|
||||||
|
|
||||||
|
_client.UserJoined += async (user) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AutoAssignedRoles.TryGetValue(user.Guild.Id, out ulong roleId);
|
||||||
|
|
||||||
|
if (roleId == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
|
||||||
|
|
||||||
|
if (role != null)
|
||||||
|
await user.AddRoleAsync(role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class GameVoiceChannelService
|
||||||
|
{
|
||||||
|
public readonly ConcurrentHashSet<ulong> GameVoiceChannels = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly DbHandler _db;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public GameVoiceChannelService(DiscordShardedClient client, DbHandler db, IEnumerable<GuildConfig> gcs)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_db = db;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
GameVoiceChannels = new ConcurrentHashSet<ulong>(
|
||||||
|
gcs.Where(gc => gc.GameVoiceChannel != null)
|
||||||
|
.Select(gc => gc.GameVoiceChannel.Value));
|
||||||
|
|
||||||
|
_client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Client_UserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var gUser = usr as SocketGuildUser;
|
||||||
|
if (gUser == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var game = gUser.Game?.Name.TrimTo(50).ToLowerInvariant();
|
||||||
|
|
||||||
|
if (oldState.VoiceChannel == newState.VoiceChannel ||
|
||||||
|
newState.VoiceChannel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!GameVoiceChannels.Contains(newState.VoiceChannel.Id) ||
|
||||||
|
string.IsNullOrWhiteSpace(game))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var vch = gUser.Guild.VoiceChannels
|
||||||
|
.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
||||||
|
|
||||||
|
if (vch == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
await gUser.ModifyAsync(gu => gu.Channel = vch).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
src/NadekoBot/Services/Administration/PlayingRotateService.cs
Normal file
104
src/NadekoBot/Services/Administration/PlayingRotateService.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NadekoBot.Services.Music;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
//todo 99 - Could make a placeholder service, which can work for any module
|
||||||
|
//and have replacements which are dependent on the types provided in the constructor
|
||||||
|
public class PlayingRotateService
|
||||||
|
{
|
||||||
|
public List<PlayingStatus> RotatingStatusMessages { get; }
|
||||||
|
public volatile bool RotatingStatuses;
|
||||||
|
private readonly Timer _t;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly BotConfig _bc;
|
||||||
|
private readonly MusicService _music;
|
||||||
|
private readonly Logger _log;
|
||||||
|
|
||||||
|
private class TimerState
|
||||||
|
{
|
||||||
|
public int Index { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayingRotateService(DiscordShardedClient client, BotConfig bc, MusicService music)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_bc = bc;
|
||||||
|
_music = music;
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
RotatingStatusMessages = _bc.RotatingStatusMessages;
|
||||||
|
RotatingStatuses = _bc.RotatingStatuses;
|
||||||
|
|
||||||
|
_t = new Timer(async (objState) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var state = (TimerState)objState;
|
||||||
|
if (!RotatingStatuses)
|
||||||
|
return;
|
||||||
|
if (state.Index >= RotatingStatusMessages.Count)
|
||||||
|
state.Index = 0;
|
||||||
|
|
||||||
|
if (!RotatingStatusMessages.Any())
|
||||||
|
return;
|
||||||
|
var status = RotatingStatusMessages[state.Index++].Status;
|
||||||
|
if (string.IsNullOrWhiteSpace(status))
|
||||||
|
return;
|
||||||
|
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client,_music)));
|
||||||
|
var shards = _client.Shards;
|
||||||
|
for (int i = 0; i < shards.Count; i++)
|
||||||
|
{
|
||||||
|
var curShard = shards.ElementAt(i);
|
||||||
|
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard)));
|
||||||
|
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn("Rotating playing status errored.\n" + ex);
|
||||||
|
}
|
||||||
|
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, Func<DiscordShardedClient, MusicService, string>> PlayingPlaceholders { get; } =
|
||||||
|
new Dictionary<string, Func<DiscordShardedClient, MusicService, string>> {
|
||||||
|
{ "%servers%", (c, ms) => c.Guilds.Count.ToString()},
|
||||||
|
{ "%users%", (c, ms) => c.Guilds.Sum(s => s.Users.Count).ToString()},
|
||||||
|
{ "%playing%", (c, ms) => {
|
||||||
|
var cnt = ms.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
||||||
|
if (cnt != 1) return cnt.ToString();
|
||||||
|
try {
|
||||||
|
var mp = ms.MusicPlayers.FirstOrDefault();
|
||||||
|
return mp.Value.CurrentSong.SongInfo.Title;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return "No songs";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "%queued%", (c, ms) => ms.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
|
||||||
|
{ "%time%", (c, ms) => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
|
||||||
|
{ "%shardcount%", (c, ms) => c.Shards.Count.ToString() },
|
||||||
|
};
|
||||||
|
|
||||||
|
public Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =
|
||||||
|
new Dictionary<string, Func<DiscordSocketClient, string>> {
|
||||||
|
{ "%shardid%", (client) => client.ShardId.ToString()},
|
||||||
|
{ "%shardguilds%", (client) => client.Guilds.Count.ToString()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
182
src/NadekoBot/Services/Administration/ProtectionService.cs
Normal file
182
src/NadekoBot/Services/Administration/ProtectionService.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class ProtectionService
|
||||||
|
{
|
||||||
|
public readonly ConcurrentDictionary<ulong, AntiRaidStats> AntiRaidGuilds =
|
||||||
|
new ConcurrentDictionary<ulong, AntiRaidStats>();
|
||||||
|
// guildId | (userId|messages)
|
||||||
|
public readonly ConcurrentDictionary<ulong, AntiSpamStats> AntiSpamGuilds =
|
||||||
|
new ConcurrentDictionary<ulong, AntiSpamStats>();
|
||||||
|
|
||||||
|
//todo sub LogCommands to this
|
||||||
|
public event Func<IEnumerable<IGuildUser>, PunishmentAction, ProtectionType, Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; };
|
||||||
|
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
private readonly MuteService _mute;
|
||||||
|
|
||||||
|
public ProtectionService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_client = client;
|
||||||
|
_mute = mute;
|
||||||
|
|
||||||
|
foreach (var gc in gcs)
|
||||||
|
{
|
||||||
|
var raid = gc.AntiRaidSetting;
|
||||||
|
var spam = gc.AntiSpamSetting;
|
||||||
|
|
||||||
|
if (raid != null)
|
||||||
|
{
|
||||||
|
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
||||||
|
AntiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spam != null)
|
||||||
|
AntiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.MessageReceived += (imsg) =>
|
||||||
|
{
|
||||||
|
var msg = imsg as IUserMessage;
|
||||||
|
if (msg == null || msg.Author.IsBot)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var channel = msg.Channel as ITextChannel;
|
||||||
|
if (channel == null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!AntiSpamGuilds.TryGetValue(channel.Guild.Id, out var spamSettings) ||
|
||||||
|
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
||||||
|
{
|
||||||
|
ChannelId = channel.Id
|
||||||
|
}))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, (id) => new UserSpamStats(msg),
|
||||||
|
(id, old) =>
|
||||||
|
{
|
||||||
|
old.ApplyNextMessage(msg); return old;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||||
|
{
|
||||||
|
if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats))
|
||||||
|
{
|
||||||
|
stats.Dispose();
|
||||||
|
await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
_client.UserJoined += (usr) =>
|
||||||
|
{
|
||||||
|
if (usr.IsBot)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
if (!AntiRaidGuilds.TryGetValue(usr.Guild.Id, out var settings))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
if (!settings.RaidUsers.Add(usr))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
++settings.UsersCount;
|
||||||
|
|
||||||
|
if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold)
|
||||||
|
{
|
||||||
|
var users = settings.RaidUsers.ToArray();
|
||||||
|
settings.RaidUsers.Clear();
|
||||||
|
|
||||||
|
await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false);
|
||||||
|
|
||||||
|
settings.RaidUsers.TryRemove(usr);
|
||||||
|
--settings.UsersCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus)
|
||||||
|
{
|
||||||
|
_log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild");
|
||||||
|
foreach (var gu in gus)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case PunishmentAction.Mute:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _mute.MuteUser(gu).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Kick:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gu.KickAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Softban:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false);
|
||||||
|
// try it twice, really don't want to ban user if
|
||||||
|
// only kick has been specified as the punishement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Ban:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await OnAntiProtectionTriggered(gus, action, pt).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/NadekoBot/Services/Administration/ProtectionStats.cs
Normal file
26
src/NadekoBot/Services/Administration/ProtectionStats.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Discord;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public enum ProtectionType
|
||||||
|
{
|
||||||
|
Raiding,
|
||||||
|
Spamming,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AntiRaidStats
|
||||||
|
{
|
||||||
|
public AntiRaidSetting AntiRaidSettings { get; set; }
|
||||||
|
public int UsersCount { get; set; }
|
||||||
|
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AntiSpamStats
|
||||||
|
{
|
||||||
|
public AntiSpamSetting AntiSpamSettings { get; set; }
|
||||||
|
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
||||||
|
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
||||||
|
}
|
||||||
|
}
|
53
src/NadekoBot/Services/Administration/RatelimitService.cs
Normal file
53
src/NadekoBot/Services/Administration/RatelimitService.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class RatelimitService
|
||||||
|
{
|
||||||
|
public ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
||||||
|
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||||
|
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||||
|
|
||||||
|
private readonly Logger _log;
|
||||||
|
private readonly DiscordShardedClient _client;
|
||||||
|
|
||||||
|
public RatelimitService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||||
|
gcs.ToDictionary(x => x.GuildId,
|
||||||
|
x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId))));
|
||||||
|
|
||||||
|
IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||||
|
gcs.ToDictionary(x => x.GuildId,
|
||||||
|
x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId))));
|
||||||
|
|
||||||
|
_client.MessageReceived += async (umsg) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var usrMsg = umsg as SocketUserMessage;
|
||||||
|
var channel = usrMsg?.Channel as SocketTextChannel;
|
||||||
|
|
||||||
|
if (channel == null || usrMsg == null || usrMsg.IsAuthor(client))
|
||||||
|
return;
|
||||||
|
if (!RatelimitingChannels.TryGetValue(channel.Id, out Ratelimiter limiter))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser))
|
||||||
|
await usrMsg.DeleteAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
src/NadekoBot/Services/Administration/Ratelimiter.cs
Normal file
59
src/NadekoBot/Services/Administration/Ratelimiter.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using Discord.WebSocket;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class Ratelimiter
|
||||||
|
{
|
||||||
|
private readonly RatelimitService _svc;
|
||||||
|
|
||||||
|
public class RatelimitedUser
|
||||||
|
{
|
||||||
|
public ulong UserId { get; set; }
|
||||||
|
public int MessageCount { get; set; } = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
public int MaxMessages { get; set; }
|
||||||
|
public int PerSeconds { get; set; }
|
||||||
|
|
||||||
|
public Ratelimiter(RatelimitService svc)
|
||||||
|
{
|
||||||
|
_svc = svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancellationTokenSource CancelSource { get; set; } = new CancellationTokenSource();
|
||||||
|
|
||||||
|
public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
|
||||||
|
|
||||||
|
public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser)
|
||||||
|
{
|
||||||
|
if ((_svc.IgnoredUsers.TryGetValue(guildId, out HashSet<ulong> ignoreUsers) && ignoreUsers.Contains(id)) ||
|
||||||
|
(optUser != null && _svc.IgnoredRoles.TryGetValue(guildId, out HashSet<ulong> ignoreRoles) && optUser.Roles.Any(x => ignoreRoles.Contains(x.Id))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
||||||
|
if (usr.MessageCount >= MaxMessages)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
usr.MessageCount++;
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(PerSeconds * 1000, CancelSource.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
usr.MessageCount--;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,6 @@ namespace NadekoBot.Services.Administration
|
|||||||
public volatile bool ForwardDMs;
|
public volatile bool ForwardDMs;
|
||||||
public volatile bool ForwardDMsToAllOwners;
|
public volatile bool ForwardDMsToAllOwners;
|
||||||
|
|
||||||
private readonly Logger _log;
|
|
||||||
private readonly NadekoBot _bot;
|
private readonly NadekoBot _bot;
|
||||||
private readonly CommandHandler _cmdHandler;
|
private readonly CommandHandler _cmdHandler;
|
||||||
private readonly DbHandler _db;
|
private readonly DbHandler _db;
|
||||||
|
53
src/NadekoBot/Services/Administration/UserSpamStats.cs
Normal file
53
src/NadekoBot/Services/Administration/UserSpamStats.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using Discord;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Administration
|
||||||
|
{
|
||||||
|
public class UserSpamStats : IDisposable
|
||||||
|
{
|
||||||
|
public int Count => timers.Count;
|
||||||
|
public string LastMessage { get; set; }
|
||||||
|
|
||||||
|
private ConcurrentQueue<Timer> timers { get; }
|
||||||
|
|
||||||
|
public UserSpamStats(IUserMessage msg)
|
||||||
|
{
|
||||||
|
LastMessage = msg.Content.ToUpperInvariant();
|
||||||
|
timers = new ConcurrentQueue<Timer>();
|
||||||
|
|
||||||
|
ApplyNextMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly object applyLock = new object();
|
||||||
|
public void ApplyNextMessage(IUserMessage message)
|
||||||
|
{
|
||||||
|
lock (applyLock)
|
||||||
|
{
|
||||||
|
var upperMsg = message.Content.ToUpperInvariant();
|
||||||
|
if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any()))
|
||||||
|
{
|
||||||
|
LastMessage = upperMsg;
|
||||||
|
while (timers.TryDequeue(out var old))
|
||||||
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
var t = new Timer((_) => {
|
||||||
|
if (timers.TryDequeue(out var old))
|
||||||
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30));
|
||||||
|
timers.Enqueue(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
while (timers.TryDequeue(out var old))
|
||||||
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Pokemon
|
namespace NadekoBot.Services.Pokemon
|
||||||
{
|
{
|
||||||
class PokeStats
|
public class PokeStats
|
||||||
{
|
{
|
||||||
//Health left
|
//Health left
|
||||||
public int Hp { get; set; } = 500;
|
public int Hp { get; set; } = 500;
|
32
src/NadekoBot/Services/Pokemon/PokemonService.cs
Normal file
32
src/NadekoBot/Services/Pokemon/PokemonService.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services.Pokemon
|
||||||
|
{
|
||||||
|
public class PokemonService
|
||||||
|
{
|
||||||
|
public readonly List<PokemonType> PokemonTypes = new List<PokemonType>();
|
||||||
|
public readonly ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>();
|
||||||
|
|
||||||
|
public const string PokemonTypesFile = "data/pokemon_types.json";
|
||||||
|
|
||||||
|
private Logger _log { get; }
|
||||||
|
|
||||||
|
public PokemonService()
|
||||||
|
{
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
if (File.Exists(PokemonTypesFile))
|
||||||
|
{
|
||||||
|
PokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PokemonTypes = new List<PokemonType>();
|
||||||
|
_log.Warn(PokemonTypesFile + " is missing. Pokemon types not loaded.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Pokemon
|
namespace NadekoBot.Services.Pokemon
|
||||||
{
|
{
|
||||||
public class PokemonType
|
public class PokemonType
|
||||||
{
|
{
|
@ -18,6 +18,9 @@ namespace NadekoBot.Extensions
|
|||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
|
public static bool IsAuthor(this IMessage msg, IDiscordClient client) =>
|
||||||
|
msg.Author?.Id == client.CurrentUser.Id;
|
||||||
|
|
||||||
private static readonly IEmote arrow_left = Emote.Parse("⬅");
|
private static readonly IEmote arrow_left = Emote.Parse("⬅");
|
||||||
private static readonly IEmote arrow_right = Emote.Parse("➡");
|
private static readonly IEmote arrow_right = Emote.Parse("➡");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user