afk added #13
6 changed files with 141 additions and 16 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -20,6 +20,9 @@ src/EllieBot/credentials.json
|
||||||
src/EllieBot/old_credentials.json
|
src/EllieBot/old_credentials.json
|
||||||
src/EllieBot/credentials.json.bak
|
src/EllieBot/credentials.json.bak
|
||||||
src/EllieBot/data/EllieBot.db
|
src/EllieBot/data/EllieBot.db
|
||||||
|
build.ps1
|
||||||
|
build.sh
|
||||||
|
test.ps1
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/visualstudio,visualstudiocode,windows,linux,macos
|
# Created by https://www.gitignore.io/api/visualstudio,visualstudiocode,windows,linux,macos
|
||||||
|
|
||||||
|
|
|
@ -401,11 +401,10 @@ public partial class EllieExpressions : EllieModule<EllieExpressionsService>
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
#if GLOBAL_ELLIE
|
|
||||||
[OwnerOnly]
|
|
||||||
#endif
|
|
||||||
public async Task ExprsImport([Leftover] string input = null)
|
public async Task ExprsImport([Leftover] string input = null)
|
||||||
{
|
{
|
||||||
|
// todo cooldown on public bot for 1 day, limit 100
|
||||||
|
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await Response().Error(strs.expr_insuff_perms).SendAsync();
|
await Response().Error(strs.expr_insuff_perms).SendAsync();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#nullable disable
|
using LinqToDB.Reflection;
|
||||||
using EllieBot.Modules.Utility.Services;
|
using EllieBot.Modules.Utility.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -7,6 +7,8 @@ using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||||
using Microsoft.CodeAnalysis.Scripting;
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
|
using EllieBot.Common.ModuleBehaviors;
|
||||||
|
using EllieBot.Modules.Games.Hangman;
|
||||||
using EllieBot.Modules.Searches.Common;
|
using EllieBot.Modules.Searches.Common;
|
||||||
|
|
||||||
namespace EllieBot.Modules.Utility;
|
namespace EllieBot.Modules.Utility;
|
||||||
|
@ -41,6 +43,7 @@ public partial class Utility : EllieModule
|
||||||
private readonly IHttpClientFactory _httpFactory;
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
private readonly VerboseErrorsService _veService;
|
private readonly VerboseErrorsService _veService;
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
|
private readonly AfkService _afkService;
|
||||||
|
|
||||||
public Utility(
|
public Utility(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
|
@ -50,7 +53,8 @@ public partial class Utility : EllieModule
|
||||||
DownloadTracker tracker,
|
DownloadTracker tracker,
|
||||||
IHttpClientFactory httpFactory,
|
IHttpClientFactory httpFactory,
|
||||||
VerboseErrorsService veService,
|
VerboseErrorsService veService,
|
||||||
IServiceProvider services)
|
IServiceProvider services,
|
||||||
|
AfkService afkService)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_coord = coord;
|
_coord = coord;
|
||||||
|
@ -60,6 +64,7 @@ public partial class Utility : EllieModule
|
||||||
_httpFactory = httpFactory;
|
_httpFactory = httpFactory;
|
||||||
_veService = veService;
|
_veService = veService;
|
||||||
_services = services;
|
_services = services;
|
||||||
|
_afkService = afkService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@ -99,7 +104,7 @@ public partial class Utility : EllieModule
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task WhosPlaying([Leftover] string game)
|
public async Task WhosPlaying([Leftover] string? game)
|
||||||
{
|
{
|
||||||
game = game?.Trim().ToUpperInvariant();
|
game = game?.Trim().ToUpperInvariant();
|
||||||
if (string.IsNullOrWhiteSpace(game))
|
if (string.IsNullOrWhiteSpace(game))
|
||||||
|
@ -140,7 +145,7 @@ public partial class Utility : EllieModule
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[Priority(0)]
|
[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)
|
if (--page < 0)
|
||||||
return;
|
return;
|
||||||
|
@ -178,7 +183,7 @@ public partial class Utility : EllieModule
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public Task InRole([Leftover] IRole role = null)
|
public Task InRole([Leftover] IRole? role = null)
|
||||||
=> InRole(1, role);
|
=> InRole(1, role);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@ -218,7 +223,7 @@ public partial class Utility : EllieModule
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task UserId([Leftover] IGuildUser target = null)
|
public async Task UserId([Leftover] IGuildUser? target = null)
|
||||||
{
|
{
|
||||||
var usr = target ?? ctx.User;
|
var usr = target ?? ctx.User;
|
||||||
await Response()
|
await Response()
|
||||||
|
@ -248,7 +253,7 @@ public partial class Utility : EllieModule
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[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;
|
var guild = ctx.Guild;
|
||||||
|
|
||||||
|
@ -301,7 +306,7 @@ public partial class Utility : EllieModule
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ChannelTopic([Leftover] ITextChannel channel = null)
|
public async Task ChannelTopic([Leftover] ITextChannel? channel = null)
|
||||||
{
|
{
|
||||||
if (channel is null)
|
if (channel is null)
|
||||||
channel = (ITextChannel)ctx.Channel;
|
channel = (ITextChannel)ctx.Channel;
|
||||||
|
@ -382,7 +387,7 @@ public partial class Utility : EllieModule
|
||||||
[BotPerm(GuildPerm.ManageEmojisAndStickers)]
|
[BotPerm(GuildPerm.ManageEmojisAndStickers)]
|
||||||
[UserPerm(GuildPerm.ManageEmojisAndStickers)]
|
[UserPerm(GuildPerm.ManageEmojisAndStickers)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task EmojiAdd(string name, string url = null)
|
public async Task EmojiAdd(string name, string? url = null)
|
||||||
{
|
{
|
||||||
name = name.Trim(':');
|
name = name.Trim(':');
|
||||||
|
|
||||||
|
@ -456,10 +461,10 @@ public partial class Utility : EllieModule
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[BotPerm(GuildPerm.ManageEmojisAndStickers)]
|
[BotPerm(GuildPerm.ManageEmojisAndStickers)]
|
||||||
[UserPerm(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;
|
string format;
|
||||||
Stream stream = null;
|
Stream? stream = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -696,6 +701,19 @@ public partial class Utility : EllieModule
|
||||||
await Response().Confirm(strs.verbose_errors_disabled).SendAsync();
|
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]
|
[Cmd]
|
||||||
[NoPublicBot]
|
[NoPublicBot]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
|
@ -759,4 +777,96 @@ public partial class Utility : EllieModule
|
||||||
await Response().Error(ex.Message).SendAsync();
|
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<string> GetKey(ulong userId)
|
||||||
|
=> new($"afk:msg:{userId}");
|
||||||
|
|
||||||
|
public async Task<bool> 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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1410,4 +1410,6 @@ honeypot:
|
||||||
coins:
|
coins:
|
||||||
- coins
|
- coins
|
||||||
- crypto
|
- crypto
|
||||||
- cryptos
|
- cryptos
|
||||||
|
afk:
|
||||||
|
- afk
|
|
@ -4569,3 +4569,13 @@ coins:
|
||||||
params:
|
params:
|
||||||
- page:
|
- page:
|
||||||
desc: "Page number to show. Starts at 1."
|
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."
|
||||||
|
|
|
@ -1104,5 +1104,6 @@
|
||||||
"queue_search_results": "Type the number of the search result to queue up that track.",
|
"queue_search_results": "Type the number of the search result to queue up that track.",
|
||||||
"overloads": "Overloads",
|
"overloads": "Overloads",
|
||||||
"honeypot_on": "Honeypot enabled on this channel.",
|
"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."
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue