Invite filtering works

This commit is contained in:
Kwoth 2016-10-03 19:21:05 +02:00
parent 0df0eea6c0
commit f7b3b67197
6 changed files with 201 additions and 76 deletions

View File

@ -177,6 +177,42 @@ namespace NadekoBot.Migrations
b.ToTable("EightBallResponses"); b.ToTable("EightBallResponses");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<int?>("GuildConfigId");
b.Property<int?>("GuildConfigId1");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.HasIndex("GuildConfigId1");
b.ToTable("FilterChannelId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int?>("GuildConfigId");
b.Property<string>("Word");
b.HasKey("Id");
b.HasIndex("GuildConfigId");
b.ToTable("FilteredWord");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -230,6 +266,10 @@ namespace NadekoBot.Migrations
b.Property<bool>("ExclusiveSelfAssignedRoles"); b.Property<bool>("ExclusiveSelfAssignedRoles");
b.Property<bool>("FilterInvites");
b.Property<bool>("FilterWords");
b.Property<ulong?>("GenerateCurrencyChannelId"); b.Property<ulong?>("GenerateCurrencyChannelId");
b.Property<ulong>("GreetMessageChannelId"); b.Property<ulong>("GreetMessageChannelId");
@ -576,6 +616,24 @@ namespace NadekoBot.Migrations
.HasForeignKey("BotConfigId"); .HasForeignKey("BotConfigId");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
.WithMany("FilterInvitesChannelIds")
.HasForeignKey("GuildConfigId");
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
.WithMany("FilterWordsChannelIds")
.HasForeignKey("GuildConfigId1");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
.WithMany("FilteredWords")
.HasForeignKey("GuildConfigId");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b =>
{ {
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")

View File

@ -13,6 +13,7 @@ using NadekoBot.Services.Database.Models;
using NadekoBot.Modules.Permissions; using NadekoBot.Modules.Permissions;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Discord.Net; using Discord.Net;
using NadekoBot.Extensions;
namespace NadekoBot.Services namespace NadekoBot.Services
{ {
@ -33,14 +34,14 @@ namespace NadekoBot.Services
_client.MessageReceived += MessageReceivedHandler; _client.MessageReceived += MessageReceivedHandler;
} }
private Task MessageReceivedHandler(IMessage msg) private async Task MessageReceivedHandler(IMessage msg)
{ {
var usrMsg = msg as IUserMessage; var usrMsg = msg as IUserMessage;
if (usrMsg == null) if (usrMsg == null)
return Task.CompletedTask; return;
if (usrMsg.Author.IsBot) //no bots if (usrMsg.Author.IsBot) //no bots
return Task.CompletedTask; return;
var guild = (msg.Channel as ITextChannel)?.Guild; var guild = (msg.Channel as ITextChannel)?.Guild;
@ -51,83 +52,124 @@ namespace NadekoBot.Services
(bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null) (bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null)
{ {
_log.Warn("Attempt was made to run a command by a blacklisted {0}, id: {1}", blacklistedItem.Type, blacklistedItem.ItemId); _log.Warn("Attempt was made to run a command by a blacklisted {0}, id: {1}", blacklistedItem.Type, blacklistedItem.ItemId);
return Task.CompletedTask; return;
} }
var throwaway = Task.Run(async () => if (guild != null)
{ {
var sw = new Stopwatch(); if (Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
sw.Start(); Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id))
try
{ {
if (usrMsg.Content.IsDiscordInvite())
bool verbose = false;
Permission rootPerm = null;
string permRole = "";
if (guild != null)
{ {
using (var uow = DbHandler.UnitOfWork()) try
{ {
var config = uow.GuildConfigs.PermissionsFor(guild.Id); await usrMsg.DeleteAsync().ConfigureAwait(false);
verbose = config.VerbosePermissions; return;
rootPerm = config.RootPermission;
permRole = config.PermissionRole.Trim().ToLowerInvariant();
} }
} catch (HttpException ex)
var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, rootPerm, permRole, MultiMatchHandling.Best);
var command = t.Item1;
var result = t.Item2;
sw.Stop();
var channel = (usrMsg.Channel as ITextChannel);
if (result.IsSuccess)
{
CommandExecuted(this, new CommandExecutedEventArgs(usrMsg, command));
_log.Info("Command Executed after {4}s\n\t" +
"User: {0}\n\t" +
"Server: {1}\n\t" +
"Channel: {2}\n\t" +
"Message: {3}",
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content, // {3}
sw.Elapsed.TotalSeconds // {4}
);
}
else if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
{
_log.Warn("Command Errored after {5}s\n\t" +
"User: {0}\n\t" +
"Server: {1}\n\t" +
"Channel: {2}\n\t" +
"Message: {3}\n\t" +
"Error: {4}",
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content,// {3}
result.ErrorReason, // {4}
sw.Elapsed.TotalSeconds // {5}
);
if (guild != null && command != null && result.Error == CommandError.Exception)
{ {
if (verbose) _log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
await msg.Channel.SendMessageAsync(":warning: " + result.ErrorReason).ConfigureAwait(false);
} }
} }
} }
catch (Exception ex) var filteredWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id).Concat(Permissions.FilterCommands.FilteredWordsForServer(guild.Id));
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
if (filteredWords.Any())
{ {
_log.Warn(ex, "Error in CommandHandler"); try
if(ex.InnerException != null) {
_log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler"); await usrMsg.DeleteAsync().ConfigureAwait(false);
return;
}
catch (HttpException ex)
{
_log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
}
} }
}); }
return Task.CompletedTask; try
{
bool verbose = false;
Permission rootPerm = null;
string permRole = "";
if (guild != null)
{
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.PermissionsFor(guild.Id);
verbose = config.VerbosePermissions;
rootPerm = config.RootPermission;
permRole = config.PermissionRole.Trim().ToLowerInvariant();
}
}
var throwaway = Task.Run(async () =>
{
var sw = new Stopwatch();
sw.Start();
try
{
var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, rootPerm, permRole, MultiMatchHandling.Best);
var command = t.Item1;
var result = t.Item2;
sw.Stop();
var channel = (usrMsg.Channel as ITextChannel);
if (result.IsSuccess)
{
CommandExecuted(this, new CommandExecutedEventArgs(usrMsg, command));
_log.Info("Command Executed after {4}s\n\t" +
"User: {0}\n\t" +
"Server: {1}\n\t" +
"Channel: {2}\n\t" +
"Message: {3}",
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content, // {3}
sw.Elapsed.TotalSeconds // {4}
);
}
else if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
{
_log.Warn("Command Errored after {5}s\n\t" +
"User: {0}\n\t" +
"Server: {1}\n\t" +
"Channel: {2}\n\t" +
"Message: {3}\n\t" +
"Error: {4}",
usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content,// {3}
result.ErrorReason, // {4}
sw.Elapsed.TotalSeconds // {5}
);
if (guild != null && command != null && result.Error == CommandError.Exception)
{
if (verbose)
await msg.Channel.SendMessageAsync(":warning: " + result.ErrorReason).ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
_log.Warn(ex, "Error in CommandHandler");
if (ex.InnerException != null)
_log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler");
}
});
}
catch (Exception ex)
{
_log.Error(ex, "Error in the outter scope of the commandhandler.");
if (ex.InnerException != null)
_log.Error(ex.InnerException, "Inner exception: ");
}
} }
public async Task<Tuple<Command,IResult>> ExecuteCommand(IUserMessage message, string input, IGuild guild, IUser user, Permission rootPerm, string permRole, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Best) { public async Task<Tuple<Command,IResult>> ExecuteCommand(IUserMessage message, string input, IGuild guild, IUser user, Permission rootPerm, string permRole, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Best) {

View File

@ -46,5 +46,23 @@ namespace NadekoBot.Services.Database.Models
public Permission RootPermission { get; set; } public Permission RootPermission { get; set; }
public bool VerbosePermissions { get; set; } public bool VerbosePermissions { get; set; }
public string PermissionRole { get; set; } = "Nadeko"; public string PermissionRole { get; set; } = "Nadeko";
//filtering
public bool FilterInvites { get; set; }
public HashSet<FilterChannelId> FilterInvitesChannelIds { get; set; }
public bool FilterWords { get; set; }
public HashSet<FilteredWord> FilteredWords { get; set; }
public HashSet<FilterChannelId> FilterWordsChannelIds { get; set; }
}
public class FilterChannelId :DbEntity
{
public ulong ChannelId { get; set; }
}
public class FilteredWord :DbEntity
{
public string Word { get; set; }
} }
} }

View File

@ -23,6 +23,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl
.ThenInclude(gc => gc.Previous) .ThenInclude(gc => gc.Previous)
.Include(gc => gc.RootPermission) .Include(gc => gc.RootPermission)
.ThenInclude(gc => gc.Next) .ThenInclude(gc => gc.Next)
.Include(gc => gc.FilterInvitesChannelIds)
.Include(gc => gc.FilterWordsChannelIds)
.Include(gc => gc.FilteredWords)
.ToList(); .ToList();
/// <summary> /// <summary>
@ -37,6 +40,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl
.ThenInclude(ls => ls.IgnoredChannels) .ThenInclude(ls => ls.IgnoredChannels)
.Include(gc => gc.LogSetting) .Include(gc => gc.LogSetting)
.ThenInclude(ls => ls.IgnoredVoicePresenceChannelIds) .ThenInclude(ls => ls.IgnoredVoicePresenceChannelIds)
.Include(gc => gc.FilterInvitesChannelIds)
.Include(gc => gc.FilterWordsChannelIds)
.Include(gc => gc.FilteredWords)
.FirstOrDefault(c => c.GuildId == guildId); .FirstOrDefault(c => c.GuildId == guildId);
if (config == null) if (config == null)

View File

@ -298,5 +298,10 @@ namespace NadekoBot.Extensions
imageStream.Position = 0; imageStream.Position = 0;
return imageStream; return imageStream;
} }
private static readonly Regex filterRegex = new Regex(@"(?:discord(?:\.gg|app\.com\/invite)\/(?<id>([\w]{16}|(?:[\w]+-?){3})))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static bool IsDiscordInvite(this string str)
=> filterRegex.IsMatch(str);
} }
} }

View File

@ -40,9 +40,11 @@ namespace Tests
root.Prepend(new Permission() { SecondaryTargetName = "Added" }); root.Prepend(new Permission() { SecondaryTargetName = "Added" });
root = root.GetRoot();
Assert.Equal(11, root.Count()); Assert.Equal(11, root.Count());
Assert.Equal("Added", root.AsEnumerable().Last().SecondaryTargetName); Assert.Equal("Added", root.AsEnumerable().First().SecondaryTargetName);
} }
[Fact] [Fact]
@ -87,15 +89,9 @@ namespace Tests
Assert.Equal("3", removed.SecondaryTargetName); Assert.Equal("3", removed.SecondaryTargetName);
Assert.Equal(9, root.Count()); Assert.Equal(9, root.Count());
Assert.Throws(typeof(IndexOutOfRangeException), () => { root.RemoveAt(0); });
var temp = root.Next; Assert.Throws(typeof(IndexOutOfRangeException), () => { root.RemoveAt(9); });
removed = root.RemoveAt(0); Assert.Throws(typeof(IndexOutOfRangeException), () => { root.RemoveAt(-1); });
Assert.Equal(8, temp.Count());
Assert.Equal(null, temp.Previous);
Assert.Throws(typeof(IndexOutOfRangeException), () => { temp.RemoveAt(8); });
Assert.Throws(typeof(IndexOutOfRangeException), () => { temp.RemoveAt(-1); });
} }
[Fact] [Fact]