From 41247c68a662130cfa82e65abf96708c7f70ed96 Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 16:40:36 -0500 Subject: [PATCH 1/7] Add disabling front/latch autoproxy per-member --- PluralKit.Bot/Commands/CommandTree.cs | 5 +++- PluralKit.Bot/Commands/MemberEdit.cs | 27 +++++++++++++++++++ PluralKit.Bot/Proxy/ProxyMatcher.cs | 2 +- PluralKit.Core/Database/Database.cs | 2 +- .../Database/Functions/ProxyMember.cs | 2 ++ .../Database/Functions/functions.sql | 8 ++++-- PluralKit.Core/Database/Migrations/12.sql | 5 ++++ PluralKit.Core/Models/PKMember.cs | 1 + PluralKit.Core/Models/Patch/MemberPatch.cs | 2 ++ docs/content/command-list.md | 1 + docs/content/user-guide.md | 12 +++++++++ 11 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 PluralKit.Core/Database/Migrations/12.sql diff --git a/PluralKit.Bot/Commands/CommandTree.cs b/PluralKit.Bot/Commands/CommandTree.cs index 5561fe99..5335086a 100644 --- a/PluralKit.Bot/Commands/CommandTree.cs +++ b/PluralKit.Bot/Commands/CommandTree.cs @@ -42,6 +42,7 @@ namespace PluralKit.Bot public static Command MemberServerAvatar = new Command("member serveravatar", "member serveravatar [url|@mention]", "Changes a member's avatar in the current server"); public static Command MemberDisplayName = new Command("member displayname", "member displayname [display name]", "Changes a member's display name"); public static Command MemberServerName = new Command("member servername", "member servername [server name]", "Changes a member's display name in the current server"); + public static Command MemberAutoproxy = new Command("member autoproxy", "member autoproxy [on|off]", "Sets whether a member will be autoproxied when autoproxy is set to latch or front mode."); public static Command MemberKeepProxy = new Command("member keepproxy", "member keepproxy [on|off]", "Sets whether to include a member's proxy tags when proxying"); public static Command MemberRandom = new Command("random", "random", "Looks up a random member from your system"); public static Command MemberPrivacy = new Command("member privacy", "member privacy ", "Changes a members's privacy settings"); @@ -89,7 +90,7 @@ namespace PluralKit.Bot public static Command[] MemberCommands = { MemberInfo, MemberNew, MemberRename, MemberDisplayName, MemberServerName, MemberDesc, MemberPronouns, - MemberColor, MemberBirthday, MemberProxy, MemberKeepProxy, MemberDelete, MemberAvatar, MemberServerAvatar, MemberPrivacy, + MemberColor, MemberBirthday, MemberProxy, MemberAutoproxy, MemberKeepProxy, MemberDelete, MemberAvatar, MemberServerAvatar, MemberPrivacy, MemberRandom }; @@ -334,6 +335,8 @@ namespace PluralKit.Bot await ctx.Execute(MemberDisplayName, m => m.DisplayName(ctx, target)); else if (ctx.Match("servername", "sn", "sname", "snick", "snickname", "servernick", "servernickname", "serverdisplayname", "guildname", "guildnick", "guildnickname", "serverdn")) await ctx.Execute(MemberServerName, m => m.ServerName(ctx, target)); + else if (ctx.Match("autoproxy", "ap")) + await ctx.Execute(MemberAutoproxy, m => m.MemberAutoproxy(ctx, target)); else if (ctx.Match("keepproxy", "keeptags", "showtags")) await ctx.Execute(MemberKeepProxy, m => m.KeepProxy(ctx, target)); else if (ctx.Match("privacy")) diff --git a/PluralKit.Bot/Commands/MemberEdit.cs b/PluralKit.Bot/Commands/MemberEdit.cs index af8a2eec..3720688b 100644 --- a/PluralKit.Bot/Commands/MemberEdit.cs +++ b/PluralKit.Bot/Commands/MemberEdit.cs @@ -373,6 +373,33 @@ namespace PluralKit.Bot await ctx.Reply($"{Emojis.Success} Member proxy tags will now not be included in the resulting message when proxying."); } + public async Task MemberAutoproxy(Context ctx, PKMember target) + { + if (ctx.System == null) throw Errors.NoSystemError; + if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError; + + bool newValue; + if (ctx.Match("on", "enabled", "true", "yes") || ctx.MatchFlag("on", "enabled", "true", "yes")) newValue = true; + else if (ctx.Match("off", "disabled", "false", "no") || ctx.MatchFlag("off", "disabled", "false", "no")) newValue = false; + else if (ctx.HasNext()) throw new PKSyntaxError("You must pass either \"on\" or \"off\"."); + else + { + if (target.AllowAutoproxy) + await ctx.Reply("Latch/front autoproxy are **enabled** for this member. This member will be automatically proxied when autoproxy is set to latch or front mode."); + else + await ctx.Reply("Latch/front autoproxy are **disabled** for this member. This member will not be automatically proxied when autoproxy is set to latch or front mode."); + return; + }; + + var patch = new MemberPatch {AllowAutoproxy = Partial.Present(newValue)}; + await _db.Execute(conn => _repo.UpdateMember(conn, target.Id, patch)); + + if (newValue) + await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **enabled** for this member."); + else + await ctx.Reply($"{Emojis.Success} Latch / front autoproxy have been **disabled** for this member."); + } + public async Task Privacy(Context ctx, PKMember target, PrivacyLevel? newValueFromCommand) { if (ctx.System == null) throw Errors.NoSystemError; diff --git a/PluralKit.Bot/Proxy/ProxyMatcher.cs b/PluralKit.Bot/Proxy/ProxyMatcher.cs index cb01e4a7..386b46dd 100644 --- a/PluralKit.Bot/Proxy/ProxyMatcher.cs +++ b/PluralKit.Bot/Proxy/ProxyMatcher.cs @@ -62,7 +62,7 @@ namespace PluralKit.Bot _ => null }; - if (member == null) return false; + if (member == null || (ctx.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)) return false; match = new ProxyMatch { Content = messageContent, diff --git a/PluralKit.Core/Database/Database.cs b/PluralKit.Core/Database/Database.cs index a0436a23..72a8591e 100644 --- a/PluralKit.Core/Database/Database.cs +++ b/PluralKit.Core/Database/Database.cs @@ -19,7 +19,7 @@ namespace PluralKit.Core internal class Database: IDatabase { private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files - private const int TargetSchemaVersion = 11; + private const int TargetSchemaVersion = 12; private readonly CoreConfig _config; private readonly ILogger _logger; diff --git a/PluralKit.Core/Database/Functions/ProxyMember.cs b/PluralKit.Core/Database/Functions/ProxyMember.cs index 96becdde..fc18a582 100644 --- a/PluralKit.Core/Database/Functions/ProxyMember.cs +++ b/PluralKit.Core/Database/Functions/ProxyMember.cs @@ -19,6 +19,8 @@ namespace PluralKit.Core public string? ServerAvatar { get; } public string? Avatar { get; } + public bool AllowAutoproxy { get; } + public string ProxyName(MessageContext ctx) => ctx.SystemTag != null ? $"{ServerName ?? DisplayName ?? Name} {ctx.SystemTag}" : ServerName ?? DisplayName ?? Name; diff --git a/PluralKit.Core/Database/Functions/functions.sql b/PluralKit.Core/Database/Functions/functions.sql index 227450ab..1a0ff7f9 100644 --- a/PluralKit.Core/Database/Functions/functions.sql +++ b/PluralKit.Core/Database/Functions/functions.sql @@ -62,7 +62,9 @@ create function proxy_members(account_id bigint, guild_id bigint) name text, server_avatar text, - avatar text + avatar text, + + allow_autoproxy bool ) as $$ select @@ -78,7 +80,9 @@ as $$ -- Avatar info member_guild.avatar_url as server_avatar, - members.avatar_url as avatar + members.avatar_url as avatar, + + members.allow_autoproxy as allow_autoproxy from accounts inner join systems on systems.id = accounts.system inner join members on members.system = systems.id diff --git a/PluralKit.Core/Database/Migrations/12.sql b/PluralKit.Core/Database/Migrations/12.sql new file mode 100644 index 00000000..a02ef7e1 --- /dev/null +++ b/PluralKit.Core/Database/Migrations/12.sql @@ -0,0 +1,5 @@ +-- SCHEMA VERSION 12: -- +-- Add disabling front/latch autoproxy per-member -- + +alter table members add column allow_autoproxy bool not null default true; +update info set schema_version = 12; \ No newline at end of file diff --git a/PluralKit.Core/Models/PKMember.cs b/PluralKit.Core/Models/PKMember.cs index 40a6ad8a..6976ff18 100644 --- a/PluralKit.Core/Models/PKMember.cs +++ b/PluralKit.Core/Models/PKMember.cs @@ -24,6 +24,7 @@ namespace PluralKit.Core { public bool KeepProxy { get; private set; } public Instant Created { get; private set; } public int MessageCount { get; private set; } + public bool AllowAutoproxy { get; private set; } public PrivacyLevel MemberVisibility { get; private set; } public PrivacyLevel DescriptionPrivacy { get; private set; } diff --git a/PluralKit.Core/Models/Patch/MemberPatch.cs b/PluralKit.Core/Models/Patch/MemberPatch.cs index 51a2b552..645e2b1a 100644 --- a/PluralKit.Core/Models/Patch/MemberPatch.cs +++ b/PluralKit.Core/Models/Patch/MemberPatch.cs @@ -16,6 +16,7 @@ namespace PluralKit.Core public Partial ProxyTags { get; set; } public Partial KeepProxy { get; set; } public Partial MessageCount { get; set; } + public Partial AllowAutoproxy { get; set; } public Partial Visibility { get; set; } public Partial NamePrivacy { get; set; } public Partial DescriptionPrivacy { get; set; } @@ -35,6 +36,7 @@ namespace PluralKit.Core .With("proxy_tags", ProxyTags) .With("keep_proxy", KeepProxy) .With("message_count", MessageCount) + .With("allow_autoproxy", AllowAutoproxy) .With("member_visibility", Visibility) .With("name_privacy", NamePrivacy) .With("description_privacy", DescriptionPrivacy) diff --git a/docs/content/command-list.md b/docs/content/command-list.md index 0eed6ac8..940489c0 100644 --- a/docs/content/command-list.md +++ b/docs/content/command-list.md @@ -49,6 +49,7 @@ Words in **\** or **[square brackets]** mean fill-in-the-blank. - `pk;member proxy [tags]` - Changes the proxy tags of a member. use below add/remove commands for members with multiple tag pairs. - `pk;member proxy add [tags]` - Adds a proxy tag pair to a member. - `pk;member proxy remove [tags]` - Removes a proxy tag from a member. +- `pk;member autoproxy [on|off]` - Sets whether a member will be autoproxied when autoproxy is set to latch or front mode. - `pk;member keepproxy [on|off]` - Sets whether to include a member's proxy tags in the proxied message. - `pk;member pronouns [pronouns]` - Changes the pronouns of a member. - `pk;member color [color]` - Changes the color of a member. diff --git a/docs/content/user-guide.md b/docs/content/user-guide.md index bc13a8fa..4336eb03 100644 --- a/docs/content/user-guide.md +++ b/docs/content/user-guide.md @@ -347,6 +347,18 @@ To enable member-mode autoproxying for a given server, use the following command pk;autoproxy +### Disabling front/latch autoproxy on a per-member basis +If a system uses front or latch mode autoproxy, but one member prefers to send messages through the account (and not proxy), you can disable the front and latch modes for that specific member. + + pk;member autoproxy off + +To re-enable front / latch modes for that member, use the following command: + + pk;member autoproxy on + +This will *not* disable member mode autoproxy. If you do not wish to autoproxy, please turn off autoproxy instead of setting autoproxy to a specific member. + + ## Managing switches PluralKit allows you to log member switches through the bot. Essentially, this means you can mark one or more members as *the current fronter(s)* for the duration until the next switch. From 37294b68da85a9b2a6175cadc410abd1a0279cdc Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 18:34:08 -0500 Subject: [PATCH 2/7] Add disabling autoproxy per-account --- PluralKit.Bot/Commands/Autoproxy.cs | 43 ++++++++++++++++++- PluralKit.Bot/Handlers/MessageCreated.cs | 2 +- .../Database/Functions/MessageContext.cs | 1 + .../Database/Functions/functions.sql | 8 ++-- PluralKit.Core/Database/Migrations/12.sql | 2 + .../Repository/ModelRepository.Account.cs | 21 +++++++++ PluralKit.Core/Models/Patch/AccountPatch.cs | 10 +++++ docs/content/user-guide.md | 16 +++++++ 8 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 PluralKit.Core/Database/Repository/ModelRepository.Account.cs create mode 100644 PluralKit.Core/Models/Patch/AccountPatch.cs diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index 7181c1cf..475e0647 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -22,7 +22,17 @@ namespace PluralKit.Bot public async Task AutoproxyRoot(Context ctx) { - ctx.CheckSystem().CheckGuildContext(); + ctx.CheckSystem(); + + // check account first + // this is ugly, but someone may want to disable autoproxy in DMs (since this is global) + if (ctx.Match("account", "ac")) + { + await AutoproxyAccount(ctx); + return; + } + + ctx.CheckGuildContext(); if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove")) await AutoproxyOff(ctx); @@ -122,9 +132,40 @@ namespace PluralKit.Bot default: throw new ArgumentOutOfRangeException(); } + if (!ctx.MessageContext.AllowAutoproxy) + eb.AddField("\u200b", $"{Emojis.Note} Autoproxy is currently **disabled** for your account (<@{ctx.Author.Id}>). To enable it, use `pk;autoproxy account enable`."); + return eb.Build(); } + private async Task AutoproxyAccount(Context ctx) + { + if (ctx.Match("enable", "on")) + await AutoproxyEnableDisable(ctx, true); + else if (ctx.Match("disable", "off")) + await AutoproxyEnableDisable(ctx, false); + else if (ctx.HasNext()) + throw new PKSyntaxError("You must pass either \"on\" or \"off\"."); + else + { + var statusString = ctx.MessageContext.AllowAutoproxy ? "enabled" : "disabled"; + await ctx.Reply($"Autoproxy is currently **{statusString}** for account <@{ctx.Author.Id}>.", mentions: new IMention[]{}); + } + } + + private async Task AutoproxyEnableDisable(Context ctx, bool allow) + { + var statusString = allow ? "enabled" : "disabled"; + if (ctx.MessageContext.AllowAutoproxy == allow) + { + await ctx.Reply($"{Emojis.Note} Autoproxy is already {statusString} for account <@{ctx.Author.Id}>.", mentions: new IMention[]{}); + return; + } + var patch = new AccountPatch { AllowAutoproxy = allow }; + await _db.Execute(conn => _repo.UpdateAccount(conn, ctx.Author.Id, patch)); + await ctx.Reply($"{Emojis.Success} Autoproxy {statusString} for account <@{ctx.Author.Id}>.", mentions: new IMention[]{}); + } + private Task UpdateAutoproxy(Context ctx, AutoproxyMode autoproxyMode, MemberId? autoproxyMember) { var patch = new SystemGuildPatch {AutoproxyMode = autoproxyMode, AutoproxyMember = autoproxyMember}; diff --git a/PluralKit.Bot/Handlers/MessageCreated.cs b/PluralKit.Bot/Handlers/MessageCreated.cs index 31c66075..d51fe0fc 100644 --- a/PluralKit.Bot/Handlers/MessageCreated.cs +++ b/PluralKit.Bot/Handlers/MessageCreated.cs @@ -137,7 +137,7 @@ namespace PluralKit.Bot { try { - return await _proxy.HandleIncomingMessage(shard, evt.Message, ctx, allowAutoproxy: true); + return await _proxy.HandleIncomingMessage(shard, evt.Message, ctx, allowAutoproxy: ctx.AllowAutoproxy); } catch (PKError e) { diff --git a/PluralKit.Core/Database/Functions/MessageContext.cs b/PluralKit.Core/Database/Functions/MessageContext.cs index febafdaa..428dfd1c 100644 --- a/PluralKit.Core/Database/Functions/MessageContext.cs +++ b/PluralKit.Core/Database/Functions/MessageContext.cs @@ -24,5 +24,6 @@ namespace PluralKit.Core public Instant? LastSwitchTimestamp { get; } public string? SystemTag { get; } public string? SystemAvatar { get; } + public bool AllowAutoproxy { get; } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Functions/functions.sql b/PluralKit.Core/Database/Functions/functions.sql index 1a0ff7f9..a6f3d758 100644 --- a/PluralKit.Core/Database/Functions/functions.sql +++ b/PluralKit.Core/Database/Functions/functions.sql @@ -14,12 +14,13 @@ last_switch_members int[], last_switch_timestamp timestamp, system_tag text, - system_avatar text + system_avatar text, + allow_autoproxy bool ) as $$ -- CTEs to query "static" (accessible only through args) data with - system as (select systems.* from accounts inner join systems on systems.id = accounts.system where accounts.uid = account_id), + system as (select systems.*, allow_autoproxy as account_autoproxy from accounts inner join systems on systems.id = accounts.system where accounts.uid = account_id), guild as (select * from servers where id = guild_id), last_message as (select * from messages where messages.guild = guild_id and messages.sender = account_id order by mid desc limit 1) select @@ -37,7 +38,8 @@ as $$ system_last_switch.members as last_switch_members, system_last_switch.timestamp as last_switch_timestamp, system.tag as system_tag, - system.avatar_url as system_avatar + system.avatar_url as system_avatar, + system.account_autoproxy as allow_autoproxy -- We need a "from" clause, so we just use some bogus data that's always present -- This ensure we always have exactly one row going forward, so we can left join afterwards and still get data from (select 1) as _placeholder diff --git a/PluralKit.Core/Database/Migrations/12.sql b/PluralKit.Core/Database/Migrations/12.sql index a02ef7e1..6cc63e80 100644 --- a/PluralKit.Core/Database/Migrations/12.sql +++ b/PluralKit.Core/Database/Migrations/12.sql @@ -1,5 +1,7 @@ -- SCHEMA VERSION 12: -- -- Add disabling front/latch autoproxy per-member -- +-- Add disabling autoproxy per-account -- alter table members add column allow_autoproxy bool not null default true; +alter table accounts add column allow_autoproxy bool not null default true; update info set schema_version = 12; \ No newline at end of file diff --git a/PluralKit.Core/Database/Repository/ModelRepository.Account.cs b/PluralKit.Core/Database/Repository/ModelRepository.Account.cs new file mode 100644 index 00000000..98682b0b --- /dev/null +++ b/PluralKit.Core/Database/Repository/ModelRepository.Account.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; + +using Dapper; + +namespace PluralKit.Core +{ + public partial class ModelRepository + { + public async Task UpdateAccount(IPKConnection conn, ulong id, AccountPatch patch) + { + _logger.Information("Updated account {accountId}: {@AccountPatch}", id, patch); + var (query, pms) = patch.Apply(UpdateQueryBuilder.Update("accounts", "uid = @uid")) + .WithConstant("uid", id) + .Build(); + await conn.ExecuteAsync(query, pms); + } + + } +} \ No newline at end of file diff --git a/PluralKit.Core/Models/Patch/AccountPatch.cs b/PluralKit.Core/Models/Patch/AccountPatch.cs new file mode 100644 index 00000000..4614d4b8 --- /dev/null +++ b/PluralKit.Core/Models/Patch/AccountPatch.cs @@ -0,0 +1,10 @@ +namespace PluralKit.Core +{ + public class AccountPatch: PatchObject + { + public Partial AllowAutoproxy { get; set; } + + public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b + .With("allow_autoproxy", AllowAutoproxy); + } +} \ No newline at end of file diff --git a/docs/content/user-guide.md b/docs/content/user-guide.md index 4336eb03..bdc0a138 100644 --- a/docs/content/user-guide.md +++ b/docs/content/user-guide.md @@ -358,6 +358,22 @@ To re-enable front / latch modes for that member, use the following command: This will *not* disable member mode autoproxy. If you do not wish to autoproxy, please turn off autoproxy instead of setting autoproxy to a specific member. +### Disabling autoproxy per-account + +It is possible to fully disable autoproxy for a certain account linked to your system. For example, you might want to do this if a specific member's name is shown on the account. + +To disable autoproxy for the current account, use the following command: + + pk;autoproxy account disable + +To re-enable autoproxy for the current account, use the following command: + + pk;autoproxy account enable + +::: tip +This subcommand can also be run in DMs. +::: + ## Managing switches PluralKit allows you to log member switches through the bot. From 8e5fb6520b9869b8384abbddfe94b435a8ec8bed Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 19:44:15 -0500 Subject: [PATCH 3/7] Add configurable autoproxy latch timeout --- PluralKit.Bot/Commands/Autoproxy.cs | 36 ++++++++++++++++++- PluralKit.Bot/Proxy/ProxyMatcher.cs | 16 +++++---- .../Database/Functions/MessageContext.cs | 1 + .../Database/Functions/functions.sql | 6 ++-- PluralKit.Core/Database/Migrations/12.sql | 2 ++ PluralKit.Core/Models/PKSystem.cs | 1 + PluralKit.Core/Models/Patch/SystemPatch.cs | 4 ++- docs/content/user-guide.md | 14 ++++++++ 8 files changed, 70 insertions(+), 10 deletions(-) diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index 475e0647..c548c82d 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -25,12 +25,17 @@ namespace PluralKit.Bot ctx.CheckSystem(); // check account first - // this is ugly, but someone may want to disable autoproxy in DMs (since this is global) + // this is ugly, but these global options should be available in DMs if (ctx.Match("account", "ac")) { await AutoproxyAccount(ctx); return; } + else if (ctx.Match("timeout", "tm")) + { + await AutoproxyTimeout(ctx); + return; + } ctx.CheckGuildContext(); @@ -138,6 +143,35 @@ namespace PluralKit.Bot return eb.Build(); } + private async Task AutoproxyTimeout(Context ctx) + { + if (!ctx.HasNext()) + { + if (ctx.System.LatchTimeout == -1) + await ctx.Reply($"You do not have a custom autoproxy timeout duration set. The default latch timeout duration is {PluralKit.Bot.ProxyMatcher.DefaultLatchExpiryTime} hour(s)."); + else if (ctx.System.LatchTimeout == 0) + await ctx.Reply("Latch timeout is currently **disabled** for your system. Latch mode autoproxy will never timeout."); + else + await ctx.Reply($"The current latch timeout duration for your system is {ctx.System.LatchTimeout} hour(s)."); + return; + } + + // todo: somehow parse a more human-friendly date format + int newTimeout; + if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove")) newTimeout = 0; + else if (ctx.Match("reset", "default")) newTimeout = -1; + else if (!int.TryParse(ctx.RemainderOrNull(), out newTimeout)) throw new PKError("Duration must be an integer."); + + await _db.Execute(conn => _repo.UpdateSystem(conn, ctx.System.Id, new SystemPatch{LatchTimeout = newTimeout})); + + if (newTimeout == -1) + await ctx.Reply($"{Emojis.Success} Latch timeout reset to default ({PluralKit.Bot.ProxyMatcher.DefaultLatchExpiryTime} hours)."); + else if (newTimeout == 0) + await ctx.Reply($"{Emojis.Success} Latch timeout disabled. Latch mode autoproxy will never timeout."); + else + await ctx.Reply($"{Emojis.Success} Latch timeout set to {newTimeout} hours."); + } + private async Task AutoproxyAccount(Context ctx) { if (ctx.Match("enable", "on")) diff --git a/PluralKit.Bot/Proxy/ProxyMatcher.cs b/PluralKit.Bot/Proxy/ProxyMatcher.cs index 386b46dd..7e9aa0cf 100644 --- a/PluralKit.Bot/Proxy/ProxyMatcher.cs +++ b/PluralKit.Bot/Proxy/ProxyMatcher.cs @@ -10,7 +10,7 @@ namespace PluralKit.Bot public class ProxyMatcher { private static readonly char AutoproxyEscapeCharacter = '\\'; - private static readonly Duration LatchExpiryTime = Duration.FromHours(6); + public static readonly int DefaultLatchExpiryTime = 6; private readonly IClock _clock; private readonly ProxyTagParser _parser; @@ -56,7 +56,7 @@ namespace PluralKit.Bot AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 => members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]), - AutoproxyMode.Latch when ctx.LastMessageMember != null && !IsLatchExpired(ctx.LastMessage) => + AutoproxyMode.Latch when ctx.LastMessageMember != null && !IsLatchExpired(ctx) => members.FirstOrDefault(m => m.Id == ctx.LastMessageMember.Value), _ => null @@ -75,11 +75,15 @@ namespace PluralKit.Bot return true; } - private bool IsLatchExpired(ulong? messageId) + private bool IsLatchExpired(MessageContext ctx) { - if (messageId == null) return true; - var timestamp = DiscordUtils.SnowflakeToInstant(messageId.Value); - return _clock.GetCurrentInstant() - timestamp > LatchExpiryTime; + if (ctx.LastMessage == null) return true; + if (ctx.LatchTimeout == 0) return false; + + var timeout = Duration.FromHours(ctx.LatchTimeout == -1 ? DefaultLatchExpiryTime : ctx.LatchTimeout); + + var timestamp = DiscordUtils.SnowflakeToInstant(ctx.LastMessage.Value); + return _clock.GetCurrentInstant() - timestamp > timeout; } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Functions/MessageContext.cs b/PluralKit.Core/Database/Functions/MessageContext.cs index 428dfd1c..5d76890f 100644 --- a/PluralKit.Core/Database/Functions/MessageContext.cs +++ b/PluralKit.Core/Database/Functions/MessageContext.cs @@ -25,5 +25,6 @@ namespace PluralKit.Core public string? SystemTag { get; } public string? SystemAvatar { get; } public bool AllowAutoproxy { get; } + public int LatchTimeout { get; } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Functions/functions.sql b/PluralKit.Core/Database/Functions/functions.sql index a6f3d758..f959f447 100644 --- a/PluralKit.Core/Database/Functions/functions.sql +++ b/PluralKit.Core/Database/Functions/functions.sql @@ -15,7 +15,8 @@ last_switch_timestamp timestamp, system_tag text, system_avatar text, - allow_autoproxy bool + allow_autoproxy bool, + latch_timeout integer ) as $$ -- CTEs to query "static" (accessible only through args) data @@ -39,7 +40,8 @@ as $$ system_last_switch.timestamp as last_switch_timestamp, system.tag as system_tag, system.avatar_url as system_avatar, - system.account_autoproxy as allow_autoproxy + system.account_autoproxy as allow_autoproxy, + system.latch_timeout as latch_timeout -- We need a "from" clause, so we just use some bogus data that's always present -- This ensure we always have exactly one row going forward, so we can left join afterwards and still get data from (select 1) as _placeholder diff --git a/PluralKit.Core/Database/Migrations/12.sql b/PluralKit.Core/Database/Migrations/12.sql index 6cc63e80..c00d8e74 100644 --- a/PluralKit.Core/Database/Migrations/12.sql +++ b/PluralKit.Core/Database/Migrations/12.sql @@ -1,7 +1,9 @@ -- SCHEMA VERSION 12: -- -- Add disabling front/latch autoproxy per-member -- -- Add disabling autoproxy per-account -- +-- Add configurable latch timeout -- alter table members add column allow_autoproxy bool not null default true; alter table accounts add column allow_autoproxy bool not null default true; +alter table systems add column latch_timeout int not null default -1; update info set schema_version = 12; \ No newline at end of file diff --git a/PluralKit.Core/Models/PKSystem.cs b/PluralKit.Core/Models/PKSystem.cs index 9962e75f..462e04a4 100644 --- a/PluralKit.Core/Models/PKSystem.cs +++ b/PluralKit.Core/Models/PKSystem.cs @@ -18,6 +18,7 @@ namespace PluralKit.Core { public Instant Created { get; } public string UiTz { get; set; } public bool PingsEnabled { get; } + public int LatchTimeout { get; } public PrivacyLevel DescriptionPrivacy { get; } public PrivacyLevel MemberListPrivacy { get;} public PrivacyLevel FrontPrivacy { get; } diff --git a/PluralKit.Core/Models/Patch/SystemPatch.cs b/PluralKit.Core/Models/Patch/SystemPatch.cs index d574e8e2..76fdfbb1 100644 --- a/PluralKit.Core/Models/Patch/SystemPatch.cs +++ b/PluralKit.Core/Models/Patch/SystemPatch.cs @@ -15,6 +15,7 @@ namespace PluralKit.Core public Partial FrontPrivacy { get; set; } public Partial FrontHistoryPrivacy { get; set; } public Partial PingsEnabled { get; set; } + public Partial LatchTimeout { get; set; } public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b .With("name", Name) @@ -28,6 +29,7 @@ namespace PluralKit.Core .With("group_list_privacy", GroupListPrivacy) .With("front_privacy", FrontPrivacy) .With("front_history_privacy", FrontHistoryPrivacy) - .With("pings_enabled", PingsEnabled); + .With("pings_enabled", PingsEnabled) + .With("latch_timeout", LatchTimeout); } } \ No newline at end of file diff --git a/docs/content/user-guide.md b/docs/content/user-guide.md index bdc0a138..f7d7240b 100644 --- a/docs/content/user-guide.md +++ b/docs/content/user-guide.md @@ -340,6 +340,20 @@ To enable latch-mode autoproxying for a given server, use the following command: pk;autoproxy latch +::: tip +By default, latch mode times out after 6 hours. It is possible to change this: + + pk;autoproxy timeout + +To reset the duration, use the following command: + + pk;autoproxy timeout reset + +To disable timeout (never timeout), use the following command: + + pk;autoproxy timeout disable +::: + #### Member mode This autoproxy mode will autoproxy for a specific selected member, irrelevant of past proxies or fronters. From 68b439257d50c1399cb4d793632def6b3ae37c3f Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 20:26:34 -0500 Subject: [PATCH 4/7] Tweak documentation --- PluralKit.Bot/Commands/Autoproxy.cs | 1 + docs/content/user-guide.md | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index c548c82d..a77252e3 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -174,6 +174,7 @@ namespace PluralKit.Bot private async Task AutoproxyAccount(Context ctx) { + // todo: this might be useful elsewhere, consider moving it to ctx.MatchToggle if (ctx.Match("enable", "on")) await AutoproxyEnableDisable(ctx, true); else if (ctx.Match("disable", "off")) diff --git a/docs/content/user-guide.md b/docs/content/user-guide.md index f7d7240b..313652f5 100644 --- a/docs/content/user-guide.md +++ b/docs/content/user-guide.md @@ -315,17 +315,23 @@ Since the messages will be posted by PluralKit's webhook, there's no way to dele To delete a PluralKit-proxied message, you can react to it with the :x: emoji. Note that this only works if the message has been sent from your own account. -### Autoproxying +## Autoproxy The bot's *autoproxy* feature allows you to have messages be proxied without directly including the proxy tags. Autoproxy can be set up in various ways. There are three autoproxy modes currently implemented: To see your system's current autoproxy settings, simply use the command: + pk;autoproxy To disable autoproxying for the current server, use the command: + pk;autoproxy off *(hint: `pk;autoproxy` can be shortened to `pk;ap` in all related commands)* +::: tip +To disable autoproxy for a single message, add a backslash (`\`) to the beginning of your message. +::: + #### Front mode This autoproxy mode will proxy messages as the current *first* fronter of the system. If you register a switch with `Alice` and `Bob`, messages without proxy tags will be autoproxied as `Alice`. To enable front-mode autoproxying for a given server, use the following command: @@ -340,7 +346,14 @@ To enable latch-mode autoproxying for a given server, use the following command: pk;autoproxy latch -::: tip +#### Member mode +This autoproxy mode will autoproxy for a specific selected member, irrelevant of past proxies or fronters. + +To enable member-mode autoproxying for a given server, use the following command, where `` is a member name (in "quotes" if multiple words) or 5-letter ID: + + pk;autoproxy + +### Changing the latch timeout duration By default, latch mode times out after 6 hours. It is possible to change this: pk;autoproxy timeout @@ -352,14 +365,6 @@ To reset the duration, use the following command: To disable timeout (never timeout), use the following command: pk;autoproxy timeout disable -::: - -#### Member mode -This autoproxy mode will autoproxy for a specific selected member, irrelevant of past proxies or fronters. - -To enable member-mode autoproxying for a given server, use the following command, where `` is a member name (in "quotes" if multiple words) or 5-letter ID: - - pk;autoproxy ### Disabling front/latch autoproxy on a per-member basis If a system uses front or latch mode autoproxy, but one member prefers to send messages through the account (and not proxy), you can disable the front and latch modes for that specific member. From 29d9b91299b9b6fd7218ab17931d70731bb659f4 Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 20:48:33 -0500 Subject: [PATCH 5/7] Move AutoproxyRoot to CommandTree, add documentation --- PluralKit.Bot/Commands/Autoproxy.cs | 22 ++++----------------- PluralKit.Bot/Commands/CommandTree.cs | 28 +++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index a77252e3..11d940fe 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -20,23 +20,9 @@ namespace PluralKit.Bot _repo = repo; } - public async Task AutoproxyRoot(Context ctx) + public async Task SetAutoproxyMode(Context ctx) { - ctx.CheckSystem(); - - // check account first - // this is ugly, but these global options should be available in DMs - if (ctx.Match("account", "ac")) - { - await AutoproxyAccount(ctx); - return; - } - else if (ctx.Match("timeout", "tm")) - { - await AutoproxyTimeout(ctx); - return; - } - + // no need to check account here, it's already done at CommandTree ctx.CheckGuildContext(); if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove")) @@ -143,7 +129,7 @@ namespace PluralKit.Bot return eb.Build(); } - private async Task AutoproxyTimeout(Context ctx) + public async Task AutoproxyTimeout(Context ctx) { if (!ctx.HasNext()) { @@ -172,7 +158,7 @@ namespace PluralKit.Bot await ctx.Reply($"{Emojis.Success} Latch timeout set to {newTimeout} hours."); } - private async Task AutoproxyAccount(Context ctx) + public async Task AutoproxyAccount(Context ctx) { // todo: this might be useful elsewhere, consider moving it to ctx.MatchToggle if (ctx.Match("enable", "on")) diff --git a/PluralKit.Bot/Commands/CommandTree.cs b/PluralKit.Bot/Commands/CommandTree.cs index 5335086a..6953074a 100644 --- a/PluralKit.Bot/Commands/CommandTree.cs +++ b/PluralKit.Bot/Commands/CommandTree.cs @@ -28,7 +28,9 @@ namespace PluralKit.Bot public static Command SystemFrontPercent = new Command("system frontpercent", "system [system] frontpercent [timespan]", "Shows a system's front breakdown"); public static Command SystemPing = new Command("system ping", "system ping ", "Changes your system's ping preferences"); public static Command SystemPrivacy = new Command("system privacy", "system privacy ", "Changes your system's privacy settings"); - public static Command Autoproxy = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for this server"); + public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for this server"); + public static Command AutoproxyTimeout = new Command("autoproxy", "autoproxy timeout [|off|reset]", "Sets the latch timeout duration for your system"); + public static Command AutoproxyAccount = new Command("autoproxy", "autoproxy account [on|off]", "Toggles autoproxy globally for the current account"); public static Command MemberInfo = new Command("member", "member ", "Looks up information about a member"); public static Command MemberNew = new Command("member new", "member new ", "Creates a new member"); public static Command MemberRename = new Command("member rename", "member rename ", "Renames a member"); @@ -108,6 +110,8 @@ namespace PluralKit.Bot public static Command[] SwitchCommands = {Switch, SwitchOut, SwitchMove, SwitchDelete, SwitchDeleteAll}; + public static Command[] AutoproxyCommands = {AutoproxySet, AutoproxyTimeout, AutoproxyAccount}; + public static Command[] LogCommands = {LogChannel, LogChannelClear, LogEnable, LogDisable}; public static Command[] BlacklistCommands = {BlacklistAdd, BlacklistRemove, BlacklistShow}; @@ -133,7 +137,7 @@ namespace PluralKit.Bot if (ctx.Match("commands", "cmd", "c")) return CommandHelpRoot(ctx); if (ctx.Match("ap", "autoproxy", "auto")) - return ctx.Execute(Autoproxy, m => m.AutoproxyRoot(ctx)); + return HandleAutoproxyCommand(ctx); if (ctx.Match("list", "find", "members", "search", "query", "l", "f", "fd")) return ctx.Execute(SystemList, m => m.MemberList(ctx, ctx.System)); if (ctx.Match("link")) @@ -457,6 +461,26 @@ namespace PluralKit.Bot } } + private Task HandleAutoproxyCommand(Context ctx) + { + // todo: merge this with the changes from #251 + if (ctx.Match("commands")) + return PrintCommandList(ctx, "autoproxy", AutoproxyCommands); + + // ctx.CheckSystem(); + // oops, that breaks stuff! PKErrors before ctx.Execute don't actually do anything. + // so we just emulate checking and throwing an error. + if (ctx.System == null) + return ctx.Reply($"{Emojis.Error} {Errors.NoSystemError.Message}"); + + if (ctx.Match("account", "ac")) + return ctx.Execute(AutoproxyAccount, m => m.AutoproxyAccount(ctx)); + else if (ctx.Match("timeout", "tm")) + return ctx.Execute(AutoproxyTimeout, m => m.AutoproxyTimeout(ctx)); + else + return ctx.Execute(AutoproxySet, m => m.SetAutoproxyMode(ctx)); + } + private async Task PrintCommandNotFoundError(Context ctx, params Command[] potentialCommands) { var commandListStr = CreatePotentialCommandList(potentialCommands); From edb92168ea140d508a4227c47ca612c04c01c642 Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 20:52:15 -0500 Subject: [PATCH 6/7] Add documentation on the website as well --- PluralKit.Bot/Commands/CommandTree.cs | 2 +- docs/content/command-list.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/PluralKit.Bot/Commands/CommandTree.cs b/PluralKit.Bot/Commands/CommandTree.cs index 6953074a..ba5e5d96 100644 --- a/PluralKit.Bot/Commands/CommandTree.cs +++ b/PluralKit.Bot/Commands/CommandTree.cs @@ -28,7 +28,7 @@ namespace PluralKit.Bot public static Command SystemFrontPercent = new Command("system frontpercent", "system [system] frontpercent [timespan]", "Shows a system's front breakdown"); public static Command SystemPing = new Command("system ping", "system ping ", "Changes your system's ping preferences"); public static Command SystemPrivacy = new Command("system privacy", "system privacy ", "Changes your system's privacy settings"); - public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for this server"); + public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for the current server"); public static Command AutoproxyTimeout = new Command("autoproxy", "autoproxy timeout [|off|reset]", "Sets the latch timeout duration for your system"); public static Command AutoproxyAccount = new Command("autoproxy", "autoproxy account [on|off]", "Toggles autoproxy globally for the current account"); public static Command MemberInfo = new Command("member", "member ", "Looks up information about a member"); diff --git a/docs/content/command-list.md b/docs/content/command-list.md index 940489c0..274b06d1 100644 --- a/docs/content/command-list.md +++ b/docs/content/command-list.md @@ -79,6 +79,11 @@ Words in **\** or **[square brackets]** mean fill-in-the-blank. - `pk;switch delete all` - Deletes all logged switches. - `pk;switch out` - Registers a 'switch-out' - a switch with no associated members. +## Autoproxy commands +- `pk;autoproxy [off|front|latch|]` - Sets your system's autoproxy mode for the current server. +- `pk;autoproxy timeout [|off|reset]` - Sets the latch timeout duration for your system. +- `pk;autoproxy account [on|off]` - Toggles autoproxy globally for the current account. + ## Server owner commands *(all commands here require Manage Server permission)* - `pk;log channel ` - Sets the given channel to log all proxied messages. From db80b10ec52edd962f07aac5eafb6dd935383521 Mon Sep 17 00:00:00 2001 From: spiral Date: Sun, 22 Nov 2020 09:47:19 -0500 Subject: [PATCH 7/7] Add autoproxy commands in pk;commands --- PluralKit.Bot/Commands/CommandTree.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PluralKit.Bot/Commands/CommandTree.cs b/PluralKit.Bot/Commands/CommandTree.cs index ba5e5d96..9b0483be 100644 --- a/PluralKit.Bot/Commands/CommandTree.cs +++ b/PluralKit.Bot/Commands/CommandTree.cs @@ -453,7 +453,10 @@ namespace PluralKit.Bot case "bl": await PrintCommandList(ctx, "channel blacklisting", BlacklistCommands); break; - // case "autoproxy": (add this when #232 is merged) + case "autoproxy": + case "ap": + await PrintCommandList(ctx, "autoproxy", AutoproxyCommands); + break; // todo: are there any commands that still need to be added? default: await ctx.Reply("For the full list of commands, see the website: ");