From a8a4c9fb44c7316aa3c6d567f7fe2d354c51f299 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 5 Jul 2021 21:14:30 +0200 Subject: [PATCH] - NoPublicBotAttribute will now be properly ignored when built with GlobalNadeko configuration - Added ILogCommandsService which will have dummy implementation on public bot, this means Logging Commands will be present on public bot to pull up help etc - When .ve is enabled, NoPublicBot commands will show a nicer error message with link to selfhosting guide (thx ene) - Fixed xp gain and .xp command not working on new users - General cleanup --- src/NadekoBot/Bot.cs | 13 +++- .../Common/NoPublicBotPrecondition.cs | 2 +- .../Db/Extensions/DiscordUserExtensions.cs | 20 +++-- .../Modules/Administration/Common/LogType.cs | 21 ++++++ .../Modules/Administration/LogCommands.cs | 11 +-- .../Services/AdministrationService.cs | 4 +- .../Services/LogCommandService.cs | 75 ++++++++++++------- .../Administration/Services/PruneService.cs | 4 +- ...ensions.cs => CustomReactionExtensions.cs} | 72 +++++++++++------- .../Modules/Games/PlantAndPickCommands.cs | 4 +- src/NadekoBot/Modules/Music/Music.cs | 4 +- .../Modules/Xp/Services/XpService.cs | 1 + src/NadekoBot/_Extensions/Extensions.cs | 10 +-- 13 files changed, 156 insertions(+), 85 deletions(-) create mode 100644 src/NadekoBot/Modules/Administration/Common/LogType.cs rename src/NadekoBot/Modules/CustomReactions/Extensions/{Extensions.cs => CustomReactionExtensions.cs} (71%) diff --git a/src/NadekoBot/Bot.cs b/src/NadekoBot/Bot.cs index 55e36689b..17b36ad8d 100644 --- a/src/NadekoBot/Bot.cs +++ b/src/NadekoBot/Bot.cs @@ -18,6 +18,7 @@ using Discord.Net; using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Common.Configs; using NadekoBot.Db; +using NadekoBot.Modules.Administration.Services; using Serilog; namespace NadekoBot @@ -116,6 +117,12 @@ namespace NadekoBot .AddMemoryCache() // music .AddMusic() + // admin +#if GLOBAL_NADEKO + .AddSingleton() +#else + .AddSingleton() +#endif ; svcs.AddHttpClient(); @@ -145,7 +152,11 @@ namespace NadekoBot typeof(IEarlyBehavior), typeof(ILateBlocker), typeof(IInputTransformer), - typeof(ILateExecutor))) + typeof(ILateExecutor)) +#if GLOBAL_NADEKO + .WithoutAttribute() +#endif + ) .AsSelfWithInterfaces() .WithSingletonLifetime() ); diff --git a/src/NadekoBot/Common/NoPublicBotPrecondition.cs b/src/NadekoBot/Common/NoPublicBotPrecondition.cs index 2b5ce4586..f17f885a1 100644 --- a/src/NadekoBot/Common/NoPublicBotPrecondition.cs +++ b/src/NadekoBot/Common/NoPublicBotPrecondition.cs @@ -10,7 +10,7 @@ namespace NadekoBot.Common public override Task CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) { #if GLOBAL_NADEKO - return Task.FromResult(PreconditionResult.FromError("Not available on the public bot")); + return Task.FromResult(PreconditionResult.FromError("Not available on the public bot. To learn how to selfhost a private bot, click [here](https://nadekobot.readthedocs.io/en/latest/).")); #else return Task.FromResult(PreconditionResult.FromSuccess()); #endif diff --git a/src/NadekoBot/Db/Extensions/DiscordUserExtensions.cs b/src/NadekoBot/Db/Extensions/DiscordUserExtensions.cs index 3cbcc905c..f6780a50f 100644 --- a/src/NadekoBot/Db/Extensions/DiscordUserExtensions.cs +++ b/src/NadekoBot/Db/Extensions/DiscordUserExtensions.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Discord; using System.Collections.Generic; +using LinqToDB; using NadekoBot.Services.Database; namespace NadekoBot.Db @@ -11,16 +12,25 @@ namespace NadekoBot.Db { public static void EnsureUserCreated(this NadekoContext ctx, ulong userId, string username, string discrim, string avatarId) { - ctx.Database.ExecuteSqlInterpolated($@" + var rows = ctx.Database.ExecuteSqlInterpolated($@" UPDATE OR IGNORE DiscordUser SET Username={username}, Discriminator={discrim}, AvatarId={avatarId} -WHERE UserId={userId}; +WHERE UserId={userId};"); -INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId) -VALUES ({userId}, {username}, {discrim}, {avatarId}); -"); + if (rows == 0) + { + ctx.DiscordUser + .Add(new DiscordUser() + { + UserId = userId, + Username = username, + Discriminator = discrim, + AvatarId = avatarId, + }); + ctx.SaveChanges(); + } } //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown diff --git a/src/NadekoBot/Modules/Administration/Common/LogType.cs b/src/NadekoBot/Modules/Administration/Common/LogType.cs new file mode 100644 index 000000000..405365cc6 --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Common/LogType.cs @@ -0,0 +1,21 @@ +namespace NadekoBot.Modules.Administration +{ + public enum LogType + { + Other, + MessageUpdated, + MessageDeleted, + UserJoined, + UserLeft, + UserBanned, + UserUnbanned, + UserUpdated, + ChannelCreated, + ChannelDestroyed, + ChannelUpdated, + UserPresence, + VoicePresence, + VoicePresenceTTS, + UserMuted + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/LogCommands.cs b/src/NadekoBot/Modules/Administration/LogCommands.cs index 5b27b3d67..46c306c3c 100644 --- a/src/NadekoBot/Modules/Administration/LogCommands.cs +++ b/src/NadekoBot/Modules/Administration/LogCommands.cs @@ -1,5 +1,4 @@ -#if !GLOBAL_NADEKO -using Discord; +using Discord; using Discord.Commands; using NadekoBot.Common; using NadekoBot.Common.Attributes; @@ -10,7 +9,6 @@ using NadekoBot.Modules.Administration.Services; using System; using System.Linq; using System.Threading.Tasks; -using static NadekoBot.Modules.Administration.Services.LogCommandService; namespace NadekoBot.Modules.Administration { @@ -18,7 +16,7 @@ namespace NadekoBot.Modules.Administration { [Group] [NoPublicBot] - public class LogCommands : NadekoSubmodule + public class LogCommands : NadekoSubmodule { public enum EnableDisable { @@ -61,11 +59,11 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task LogEvents() { - _service.GuildLogSettings.TryGetValue(ctx.Guild.Id, out LogSetting l); + var logSetting = _service.GetGuildLogSettings(ctx.Guild.Id); var str = string.Join("\n", Enum.GetNames(typeof(LogType)) .Select(x => { - var val = l is null ? null : GetLogProperty(l, Enum.Parse(x)); + var val = logSetting is null ? null : GetLogProperty(logSetting, Enum.Parse(x)); if (val != null) return $"{Format.Bold(x)} <#{val}>"; return Format.Bold(x); @@ -131,4 +129,3 @@ namespace NadekoBot.Modules.Administration } } } -#endif diff --git a/src/NadekoBot/Modules/Administration/Services/AdministrationService.cs b/src/NadekoBot/Modules/Administration/Services/AdministrationService.cs index 9cebb96b4..3f59a9e1e 100644 --- a/src/NadekoBot/Modules/Administration/Services/AdministrationService.cs +++ b/src/NadekoBot/Modules/Administration/Services/AdministrationService.cs @@ -23,10 +23,10 @@ namespace NadekoBot.Modules.Administration.Services public ConcurrentDictionary DeleteMessagesOnCommandChannels { get; } private readonly DbService _db; - private readonly LogCommandService _logService; + private readonly ILogCommandService _logService; public AdministrationService(Bot bot, CommandHandler cmdHandler, DbService db, - LogCommandService logService) + ILogCommandService logService) { _db = db; _logService = logService; diff --git a/src/NadekoBot/Modules/Administration/Services/LogCommandService.cs b/src/NadekoBot/Modules/Administration/Services/LogCommandService.cs index b5211ebae..f66afa39c 100644 --- a/src/NadekoBot/Modules/Administration/Services/LogCommandService.cs +++ b/src/NadekoBot/Modules/Administration/Services/LogCommandService.cs @@ -1,5 +1,4 @@ -#if !GLOBAL_NADEKO -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -18,7 +17,43 @@ using NadekoBot.Modules.Administration.Common; namespace NadekoBot.Modules.Administration.Services { - public class LogCommandService : INService + public interface ILogCommandService + { + void AddDeleteIgnore(ulong xId); + Task LogServer(ulong guildId, ulong channelId, bool actionValue); + bool LogIgnore(ulong guildId, ulong channelId); + LogSetting GetGuildLogSettings(ulong guildId); + bool Log(ulong guildId, ulong? channelId, LogType type); + } + + public sealed class DummyLogCommandService : ILogCommandService + { + public void AddDeleteIgnore(ulong xId) + { + } + + public Task LogServer(ulong guildId, ulong channelId, bool actionValue) + { + return Task.CompletedTask; + } + + public bool LogIgnore(ulong guildId, ulong channelId) + { + return false; + } + + public LogSetting GetGuildLogSettings(ulong guildId) + { + return default; + } + + public bool Log(ulong guildId, ulong? channelId, LogType type) + { + return false; + } + } + + public sealed class LogCommandService : ILogCommandService { private readonly DiscordSocketClient _client; @@ -46,6 +81,8 @@ namespace NadekoBot.Modules.Administration.Services _prot = prot; _tz = tz; +#if !GLOBAL_NADEKO + using (var uow = db.GetDbContext()) { var guildIds = client.Guilds.Select(x => x.Id).ToList(); @@ -92,9 +129,7 @@ namespace NadekoBot.Modules.Administration.Services _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; _client.GuildMemberUpdated += _client_GuildUserUpdated; -#if !GLOBAL_NADEKO _client.UserUpdated += _client_UserUpdated; -#endif _client.ChannelCreated += _client_ChannelCreated; _client.ChannelDestroyed += _client_ChannelDestroyed; _client.ChannelUpdated += _client_ChannelUpdated; @@ -109,12 +144,20 @@ namespace NadekoBot.Modules.Administration.Services { _ignoreMessageIds.Clear(); }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + +#endif } private readonly Timer _clearTimer; private readonly ConcurrentHashSet _ignoreMessageIds = new ConcurrentHashSet(); private readonly IMemoryCache _memoryCache; + public LogSetting GetGuildLogSettings(ulong guildId) + { + GuildLogSettings.TryGetValue(guildId, out LogSetting logSetting); + return logSetting; + } + public void AddDeleteIgnore(ulong messageId) { _ignoreMessageIds.Add(messageId); @@ -1129,25 +1172,6 @@ namespace NadekoBot.Modules.Administration.Services return Task.CompletedTask; } - public enum LogType - { - Other, - MessageUpdated, - MessageDeleted, - UserJoined, - UserLeft, - UserBanned, - UserUnbanned, - UserUpdated, - ChannelCreated, - ChannelDestroyed, - ChannelUpdated, - UserPresence, - VoicePresence, - VoicePresenceTTS, - UserMuted - } - private async Task TryGetLogChannel(IGuild guild, LogSetting logSetting, LogType logChannelType) { ulong? id = null; @@ -1276,5 +1300,4 @@ namespace NadekoBot.Modules.Administration.Services } } } -} -#endif +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Services/PruneService.cs b/src/NadekoBot/Modules/Administration/Services/PruneService.cs index 8a5186f30..ab895bd0f 100644 --- a/src/NadekoBot/Modules/Administration/Services/PruneService.cs +++ b/src/NadekoBot/Modules/Administration/Services/PruneService.cs @@ -14,9 +14,9 @@ namespace NadekoBot.Modules.Administration.Services //channelids where prunes are currently occuring private ConcurrentHashSet _pruningGuilds = new ConcurrentHashSet(); private readonly TimeSpan twoWeeks = TimeSpan.FromDays(14); - private readonly LogCommandService _logService; + private readonly ILogCommandService _logService; - public PruneService(LogCommandService logService) + public PruneService(ILogCommandService logService) { this._logService = logService; } diff --git a/src/NadekoBot/Modules/CustomReactions/Extensions/Extensions.cs b/src/NadekoBot/Modules/CustomReactions/Extensions/CustomReactionExtensions.cs similarity index 71% rename from src/NadekoBot/Modules/CustomReactions/Extensions/Extensions.cs rename to src/NadekoBot/Modules/CustomReactions/Extensions/CustomReactionExtensions.cs index b95213823..4590f8573 100644 --- a/src/NadekoBot/Modules/CustomReactions/Extensions/Extensions.cs +++ b/src/NadekoBot/Modules/CustomReactions/Extensions/CustomReactionExtensions.cs @@ -15,40 +15,47 @@ using System.Threading.Tasks; namespace NadekoBot.Modules.CustomReactions.Extensions { - public static class Extensions + public static class CustomReactionExtensions { private static readonly Regex imgRegex = new Regex("%(img|image):(?.*?)%", RegexOptions.Compiled); - private static Dictionary>> regexPlaceholders { get; } = new Dictionary>>() - { - { imgRegex, async (match) => { - var tag = match.Groups["tag"].ToString(); - if(string.IsNullOrWhiteSpace(tag)) - return ""; - - var fullQueryLink = $"http://imgur.com/search?q={ tag }"; - var config = Configuration.Default.WithDefaultLoader(); - using(var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink).ConfigureAwait(false)) + private static Dictionary>> regexPlaceholders { get; } = + new Dictionary>>() + { { - var elems = document.QuerySelectorAll("a.image-list-link").ToArray(); + imgRegex, async (match) => + { + var tag = match.Groups["tag"].ToString(); + if (string.IsNullOrWhiteSpace(tag)) + return ""; - if (!elems.Any()) - return ""; + var fullQueryLink = $"http://imgur.com/search?q={tag}"; + var config = Configuration.Default.WithDefaultLoader(); + using (var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink) + .ConfigureAwait(false)) + { + var elems = document.QuerySelectorAll("a.image-list-link").ToArray(); - var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Length))?.Children?.FirstOrDefault() as IHtmlImageElement); + if (!elems.Any()) + return ""; - if (img?.Source is null) - return ""; + var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Length))?.Children + ?.FirstOrDefault() as IHtmlImageElement); - return " " + img.Source.Replace("b.", ".", StringComparison.InvariantCulture) + " "; + if (img?.Source is null) + return ""; + + return " " + img.Source.Replace("b.", ".", StringComparison.InvariantCulture) + " "; + } + } } - } } - }; + }; private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordSocketClient client) => str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal); - private static async Task ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordSocketClient client, string resolvedTrigger, bool containsAnywhere) + private static async Task ResolveResponseStringAsync(this string str, IUserMessage ctx, + DiscordSocketClient client, string resolvedTrigger, bool containsAnywhere) { var substringIndex = resolvedTrigger.Length; if (containsAnywhere) @@ -61,7 +68,7 @@ namespace NadekoBot.Modules.CustomReactions.Extensions else if (pos == WordPosition.Middle) substringIndex += ctx.Content.IndexOf(resolvedTrigger, StringComparison.InvariantCulture); } - + var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true; var rep = new ReplacementBuilder() @@ -82,12 +89,17 @@ namespace NadekoBot.Modules.CustomReactions.Extensions return str; } - public static Task ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, bool containsAnywhere) - => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client), containsAnywhere); + public static Task ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, + DiscordSocketClient client, bool containsAnywhere) + => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client), + containsAnywhere); - public static async Task Send(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, bool sanitize) + public static async Task Send(this CustomReaction cr, IUserMessage ctx, + DiscordSocketClient client, bool sanitize) { - var channel = cr.DmResponse ? await ctx.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false) : ctx.Channel; + var channel = cr.DmResponse + ? await ctx.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false) + : ctx.Channel; if (CREmbed.TryParse(cr.Response, out CREmbed crembed)) { @@ -105,7 +117,7 @@ namespace NadekoBot.Modules.CustomReactions.Extensions } var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true; - + var rep = new ReplacementBuilder() .WithDefault(ctx.Author, ctx.Channel, (ctx.Channel as ITextChannel)?.Guild as SocketGuild, client) .WithOverride("%target%", () => canMentionEveryone @@ -117,7 +129,11 @@ namespace NadekoBot.Modules.CustomReactions.Extensions return await channel.EmbedAsync(crembed, sanitize).ConfigureAwait(false); } - return await channel.SendMessageAsync((await cr.ResponseWithContextAsync(ctx, client, cr.ContainsAnywhere).ConfigureAwait(false)).SanitizeMentions(sanitize)).ConfigureAwait(false); + + return await channel + .SendMessageAsync( + (await cr.ResponseWithContextAsync(ctx, client, cr.ContainsAnywhere).ConfigureAwait(false)) + .SanitizeMentions(sanitize)).ConfigureAwait(false); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/NadekoBot/Modules/Games/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/PlantAndPickCommands.cs index 123ec1b0d..8f89e162f 100644 --- a/src/NadekoBot/Modules/Games/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/PlantAndPickCommands.cs @@ -16,9 +16,9 @@ namespace NadekoBot.Modules.Games [Group] public class PlantPickCommands : GamblingSubmodule { - private readonly LogCommandService logService; + private readonly ILogCommandService logService; - public PlantPickCommands(LogCommandService logService, GamblingConfigService gss) : base(gss) + public PlantPickCommands(ILogCommandService logService, GamblingConfigService gss) : base(gss) { this.logService = logService; } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 367f27751..b1ed07020 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -18,9 +18,9 @@ namespace NadekoBot.Modules.Music [NoPublicBot] public sealed partial class Music : NadekoModule { - private readonly LogCommandService _logService; + private readonly ILogCommandService _logService; - public Music(LogCommandService _logService) + public Music(ILogCommandService _logService) { this._logService = _logService; } diff --git a/src/NadekoBot/Modules/Xp/Services/XpService.cs b/src/NadekoBot/Modules/Xp/Services/XpService.cs index 662e42213..4067644ed 100644 --- a/src/NadekoBot/Modules/Xp/Services/XpService.cs +++ b/src/NadekoBot/Modules/Xp/Services/XpService.cs @@ -28,6 +28,7 @@ using Image = SixLabors.ImageSharp.Image; namespace NadekoBot.Modules.Xp.Services { + // todo improve xp with linqtodb public class XpService : INService { private enum NotifOf diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 79a382b8e..df111f933 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -1,7 +1,6 @@ using Discord; using Discord.Commands; using Discord.WebSocket; -using Microsoft.Extensions.DependencyInjection; using NadekoBot.Common; using NadekoBot.Common.Collections; using NadekoBot.Services; @@ -12,26 +11,19 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; -using System.Reflection; -using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using AngleSharp.Attributes; using NadekoBot.Common.Attributes; -using Serilog; namespace NadekoBot.Extensions { @@ -216,7 +208,7 @@ namespace NadekoBot.Extensions dict.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"); } - public static IMessage DeleteAfter(this IUserMessage msg, int seconds, LogCommandService logService = null) + public static IMessage DeleteAfter(this IUserMessage msg, int seconds, ILogCommandService logService = null) { if (msg is null) return null;