From 636ddac4d410a236719ae65aa1c3f0f869562289 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 17 Jul 2024 00:33:43 +1200 Subject: [PATCH] afk added This still needs some work but it is here --- .gitignore | 3 + .../Modules/Expressions/EllieExpressions.cs | 5 +- src/EllieBot/Modules/Utility/Utility.cs | 132 ++++++++++++++++-- src/EllieBot/data/aliases.yml | 4 +- .../data/strings/commands/commands.en-US.yml | 10 ++ .../strings/responses/responses.en-US.json | 3 +- 6 files changed, 141 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3b99327..8330cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ src/EllieBot/credentials.json src/EllieBot/old_credentials.json src/EllieBot/credentials.json.bak src/EllieBot/data/EllieBot.db +build.ps1 +build.sh +test.ps1 # Created by https://www.gitignore.io/api/visualstudio,visualstudiocode,windows,linux,macos diff --git a/src/EllieBot/Modules/Expressions/EllieExpressions.cs b/src/EllieBot/Modules/Expressions/EllieExpressions.cs index fab6775..b79091d 100644 --- a/src/EllieBot/Modules/Expressions/EllieExpressions.cs +++ b/src/EllieBot/Modules/Expressions/EllieExpressions.cs @@ -401,11 +401,10 @@ public partial class EllieExpressions : EllieModule } [Cmd] -#if GLOBAL_ELLIE - [OwnerOnly] -#endif public async Task ExprsImport([Leftover] string input = null) { + // todo cooldown on public bot for 1 day, limit 100 + if (!AdminInGuildOrOwnerInDm()) { await Response().Error(strs.expr_insuff_perms).SendAsync(); diff --git a/src/EllieBot/Modules/Utility/Utility.cs b/src/EllieBot/Modules/Utility/Utility.cs index e79b39d..6ec28b5 100644 --- a/src/EllieBot/Modules/Utility/Utility.cs +++ b/src/EllieBot/Modules/Utility/Utility.cs @@ -1,4 +1,4 @@ -#nullable disable +using LinqToDB.Reflection; using EllieBot.Modules.Utility.Services; using Newtonsoft.Json; using System.Diagnostics; @@ -7,6 +7,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.Scripting; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Modules.Games.Hangman; using EllieBot.Modules.Searches.Common; namespace EllieBot.Modules.Utility; @@ -41,6 +43,7 @@ public partial class Utility : EllieModule private readonly IHttpClientFactory _httpFactory; private readonly VerboseErrorsService _veService; private readonly IServiceProvider _services; + private readonly AfkService _afkService; public Utility( DiscordSocketClient client, @@ -50,7 +53,8 @@ public partial class Utility : EllieModule DownloadTracker tracker, IHttpClientFactory httpFactory, VerboseErrorsService veService, - IServiceProvider services) + IServiceProvider services, + AfkService afkService) { _client = client; _coord = coord; @@ -60,6 +64,7 @@ public partial class Utility : EllieModule _httpFactory = httpFactory; _veService = veService; _services = services; + _afkService = afkService; } [Cmd] @@ -99,7 +104,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] - public async Task WhosPlaying([Leftover] string game) + public async Task WhosPlaying([Leftover] string? game) { game = game?.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(game)) @@ -140,7 +145,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] [Priority(0)] - public async Task InRole(int page, [Leftover] IRole role = null) + public async Task InRole(int page, [Leftover] IRole? role = null) { if (--page < 0) return; @@ -178,7 +183,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] [Priority(1)] - public Task InRole([Leftover] IRole role = null) + public Task InRole([Leftover] IRole? role = null) => InRole(1, role); [Cmd] @@ -218,7 +223,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] - public async Task UserId([Leftover] IGuildUser target = null) + public async Task UserId([Leftover] IGuildUser? target = null) { var usr = target ?? ctx.User; await Response() @@ -248,7 +253,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] - public async Task Roles(IGuildUser target, int page = 1) + public async Task Roles(IGuildUser? target, int page = 1) { var guild = ctx.Guild; @@ -301,7 +306,7 @@ public partial class Utility : EllieModule [Cmd] [RequireContext(ContextType.Guild)] - public async Task ChannelTopic([Leftover] ITextChannel channel = null) + public async Task ChannelTopic([Leftover] ITextChannel? channel = null) { if (channel is null) channel = (ITextChannel)ctx.Channel; @@ -382,7 +387,7 @@ public partial class Utility : EllieModule [BotPerm(GuildPerm.ManageEmojisAndStickers)] [UserPerm(GuildPerm.ManageEmojisAndStickers)] [Priority(0)] - public async Task EmojiAdd(string name, string url = null) + public async Task EmojiAdd(string name, string? url = null) { name = name.Trim(':'); @@ -456,10 +461,10 @@ public partial class Utility : EllieModule [RequireContext(ContextType.Guild)] [BotPerm(GuildPerm.ManageEmojisAndStickers)] [UserPerm(GuildPerm.ManageEmojisAndStickers)] - public async Task StickerAdd(string name = null, string description = null, params string[] tags) + public async Task StickerAdd(string? name = null, string? description = null, params string[] tags) { string format; - Stream stream = null; + Stream? stream = null; try { @@ -696,6 +701,19 @@ public partial class Utility : EllieModule await Response().Confirm(strs.verbose_errors_disabled).SendAsync(); } + [Cmd] + public async Task Afk([Leftover] string text) + { + var succ = await _afkService.SetAfkAsync(ctx.User.Id, text); + + if (succ) + { + await Response() + .Confirm(strs.afk_set) + .SendAsync(); + } + } + [Cmd] [NoPublicBot] [OwnerOnly] @@ -759,4 +777,96 @@ public partial class Utility : EllieModule await Response().Error(ex.Message).SendAsync(); } } +} + +public sealed class AfkService : IEService, IReadyExecutor +{ + private readonly IBotCache _cache; + private readonly DiscordSocketClient _client; + private readonly MessageSenderService _mss; + + public AfkService(IBotCache cache, DiscordSocketClient client, MessageSenderService mss) + { + _cache = cache; + _client = client; + _mss = mss; + } + + private static TypedKey GetKey(ulong userId) + => new($"afk:msg:{userId}"); + + public async Task SetAfkAsync(ulong userId, string text) + { + var added = await _cache.AddAsync(GetKey(userId), text, TimeSpan.FromHours(8), overwrite: true); + return added; + } + + public Task OnReadyAsync() + { + _client.MessageReceived += TryTriggerAfkMessage; + + return Task.CompletedTask; + } + + private Task TryTriggerAfkMessage(SocketMessage arg) + { + if (arg.Author.IsBot) + return Task.CompletedTask; + + if (arg.MentionedUsers.Count is 0 or > 2) + return Task.CompletedTask; + + if (arg is not IUserMessage uMsg || uMsg.Channel is not ITextChannel tc) + return Task.CompletedTask; + + + _ = Task.Run(async () => + { + var botUser = await tc.Guild.GetCurrentUserAsync(); + + var perms = botUser.GetPermissions(tc); + + if (!perms.SendMessages) + return; + + ulong mentionedUserId = 0; + foreach (var uid in uMsg.MentionedUserIds) + { + if (uid == arg.Author.Id) + continue; + + if (arg.Content.StartsWith($"<@{uid}>") || arg.Content.StartsWith($"<@!{uid}>")) + { + mentionedUserId = uid; + break; + } + } + + if (mentionedUserId == 0) + return; + + try + { + var result = await _cache.GetAsync(GetKey(mentionedUserId)); + if (result.TryPickT0(out var msg, out _)) + { + var st = SmartText.CreateFrom(msg); + + var toDelete = await _mss.Response(arg.Channel) + .Message(uMsg) + .Text(st) + .Sanitize(false) + .SendAsync(); + + toDelete.DeleteAfter(30); + } + } + catch (HttpException ex) + { + Log.Warning("Error in afk service: {Message}", ex.Message); + } + }); + + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml index 9140342..e8c0b4c 100644 --- a/src/EllieBot/data/aliases.yml +++ b/src/EllieBot/data/aliases.yml @@ -1410,4 +1410,6 @@ honeypot: coins: - coins - crypto - - cryptos \ No newline at end of file + - cryptos +afk: + - afk \ No newline at end of file diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml index d137d44..42a69c5 100644 --- a/src/EllieBot/data/strings/commands/commands.en-US.yml +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -4569,3 +4569,13 @@ coins: params: - page: desc: "Page number to show. Starts at 1." +afk: + desc: |- + Toggles AFK status for yourself with the specified message. + Anyone @ mentioning you in any server will receive the afk message. + This will only work if the other user's message starts with the mention. + ex: + - '' + params: + - msg: + desc: "The message to send when someone pings you." diff --git a/src/EllieBot/data/strings/responses/responses.en-US.json b/src/EllieBot/data/strings/responses/responses.en-US.json index 4c0893e..37231cf 100644 --- a/src/EllieBot/data/strings/responses/responses.en-US.json +++ b/src/EllieBot/data/strings/responses/responses.en-US.json @@ -1104,5 +1104,6 @@ "queue_search_results": "Type the number of the search result to queue up that track.", "overloads": "Overloads", "honeypot_on": "Honeypot enabled on this channel.", - "honeypot_off": "Honeypot disabled." + "honeypot_off": "Honeypot disabled.", + "afk_set": "AFK message set. Type a message in any channel to clear." }