feat: rewrite database schema for localized autoproxy
This commit is contained in:
parent
ca108813b7
commit
982812333b
@ -24,11 +24,7 @@ public class DiscordControllerV2: PKControllerBase
|
|||||||
if (settings == null)
|
if (settings == null)
|
||||||
throw Errors.SystemGuildNotFound;
|
throw Errors.SystemGuildNotFound;
|
||||||
|
|
||||||
PKMember member = null;
|
return Ok(settings.ToJson());
|
||||||
if (settings.AutoproxyMember != null)
|
|
||||||
member = await _repo.GetMember(settings.AutoproxyMember.Value);
|
|
||||||
|
|
||||||
return Ok(settings.ToJson(member?.Uuid.ToString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("systems/{systemRef}/guilds/{guild_id}")]
|
[HttpPatch("systems/{systemRef}/guilds/{guild_id}")]
|
||||||
@ -42,61 +38,14 @@ public class DiscordControllerV2: PKControllerBase
|
|||||||
if (settings == null)
|
if (settings == null)
|
||||||
throw Errors.SystemGuildNotFound;
|
throw Errors.SystemGuildNotFound;
|
||||||
|
|
||||||
MemberId? memberId = null;
|
var patch = SystemGuildPatch.FromJson(data);
|
||||||
if (data.ContainsKey("autoproxy_member"))
|
|
||||||
{
|
|
||||||
if (data["autoproxy_member"].Type != JTokenType.Null)
|
|
||||||
{
|
|
||||||
var member = await ResolveMember(data.Value<string>("autoproxy_member"));
|
|
||||||
if (member == null)
|
|
||||||
throw Errors.MemberNotFound;
|
|
||||||
|
|
||||||
memberId = member.Id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memberId = settings.AutoproxyMember;
|
|
||||||
}
|
|
||||||
|
|
||||||
var patch = SystemGuildPatch.FromJson(data, memberId);
|
|
||||||
|
|
||||||
patch.AssertIsValid();
|
patch.AssertIsValid();
|
||||||
if (patch.Errors.Count > 0)
|
if (patch.Errors.Count > 0)
|
||||||
throw new ModelParseError(patch.Errors);
|
throw new ModelParseError(patch.Errors);
|
||||||
|
|
||||||
// this is less than great, but at least it's legible
|
|
||||||
if (patch.AutoproxyMember.Value == null)
|
|
||||||
{
|
|
||||||
if (patch.AutoproxyMode.IsPresent)
|
|
||||||
{
|
|
||||||
if (patch.AutoproxyMode.Value == AutoproxyMode.Member)
|
|
||||||
throw Errors.MissingAutoproxyMember;
|
|
||||||
}
|
|
||||||
else if (settings.AutoproxyMode == AutoproxyMode.Member)
|
|
||||||
{
|
|
||||||
throw Errors.MissingAutoproxyMember;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (patch.AutoproxyMode.IsPresent)
|
|
||||||
{
|
|
||||||
if (patch.AutoproxyMode.Value == AutoproxyMode.Latch)
|
|
||||||
throw Errors.PatchLatchMemberError;
|
|
||||||
}
|
|
||||||
else if (settings.AutoproxyMode == AutoproxyMode.Latch)
|
|
||||||
{
|
|
||||||
throw Errors.PatchLatchMemberError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var newSettings = await _repo.UpdateSystemGuild(system.Id, guild_id, patch);
|
var newSettings = await _repo.UpdateSystemGuild(system.Id, guild_id, patch);
|
||||||
|
return Ok(newSettings.ToJson());
|
||||||
PKMember? newMember = null;
|
|
||||||
if (newSettings.AutoproxyMember != null)
|
|
||||||
newMember = await _repo.GetMember(newSettings.AutoproxyMember.Value);
|
|
||||||
return Ok(newSettings.ToJson(newMember?.Hid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("members/{memberRef}/guilds/{guild_id}")]
|
[HttpGet("members/{memberRef}/guilds/{guild_id}")]
|
||||||
|
@ -16,25 +16,29 @@ public class Autoproxy
|
|||||||
// no need to check account here, it's already done at CommandTree
|
// no need to check account here, it's already done at CommandTree
|
||||||
ctx.CheckGuildContext();
|
ctx.CheckGuildContext();
|
||||||
|
|
||||||
|
// for now, just for guild
|
||||||
|
// this also creates settings if there are none present
|
||||||
|
var settings = await ctx.Repository.GetAutoproxySettings(ctx.System.Id, ctx.Guild.Id, null);
|
||||||
|
|
||||||
if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove"))
|
if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove"))
|
||||||
await AutoproxyOff(ctx);
|
await AutoproxyOff(ctx, settings);
|
||||||
else if (ctx.Match("latch", "last", "proxy", "stick", "sticky"))
|
else if (ctx.Match("latch", "last", "proxy", "stick", "sticky"))
|
||||||
await AutoproxyLatch(ctx);
|
await AutoproxyLatch(ctx, settings);
|
||||||
else if (ctx.Match("front", "fronter", "switch"))
|
else if (ctx.Match("front", "fronter", "switch"))
|
||||||
await AutoproxyFront(ctx);
|
await AutoproxyFront(ctx, settings);
|
||||||
else if (ctx.Match("member"))
|
else if (ctx.Match("member"))
|
||||||
throw new PKSyntaxError("Member-mode autoproxy must target a specific member. Use the `pk;autoproxy <member>` command, where `member` is the name or ID of a member in your system.");
|
throw new PKSyntaxError("Member-mode autoproxy must target a specific member. Use the `pk;autoproxy <member>` command, where `member` is the name or ID of a member in your system.");
|
||||||
else if (await ctx.MatchMember() is PKMember member)
|
else if (await ctx.MatchMember() is PKMember member)
|
||||||
await AutoproxyMember(ctx, member);
|
await AutoproxyMember(ctx, member);
|
||||||
else if (!ctx.HasNext())
|
else if (!ctx.HasNext())
|
||||||
await ctx.Reply(embed: await CreateAutoproxyStatusEmbed(ctx));
|
await ctx.Reply(embed: await CreateAutoproxyStatusEmbed(ctx, settings));
|
||||||
else
|
else
|
||||||
throw new PKSyntaxError($"Invalid autoproxy mode {ctx.PopArgument().AsCode()}.");
|
throw new PKSyntaxError($"Invalid autoproxy mode {ctx.PopArgument().AsCode()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoproxyOff(Context ctx)
|
private async Task AutoproxyOff(Context ctx, AutoproxySettings settings)
|
||||||
{
|
{
|
||||||
if (ctx.MessageContext.AutoproxyMode == AutoproxyMode.Off)
|
if (settings.AutoproxyMode == AutoproxyMode.Off)
|
||||||
{
|
{
|
||||||
await ctx.Reply($"{Emojis.Note} Autoproxy is already off in this server.");
|
await ctx.Reply($"{Emojis.Note} Autoproxy is already off in this server.");
|
||||||
}
|
}
|
||||||
@ -45,9 +49,9 @@ public class Autoproxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoproxyLatch(Context ctx)
|
private async Task AutoproxyLatch(Context ctx, AutoproxySettings settings)
|
||||||
{
|
{
|
||||||
if (ctx.MessageContext.AutoproxyMode == AutoproxyMode.Latch)
|
if (settings.AutoproxyMode == AutoproxyMode.Latch)
|
||||||
{
|
{
|
||||||
await ctx.Reply($"{Emojis.Note} Autoproxy is already set to latch mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
|
await ctx.Reply($"{Emojis.Note} Autoproxy is already set to latch mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
|
||||||
}
|
}
|
||||||
@ -58,9 +62,9 @@ public class Autoproxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoproxyFront(Context ctx)
|
private async Task AutoproxyFront(Context ctx, AutoproxySettings settings)
|
||||||
{
|
{
|
||||||
if (ctx.MessageContext.AutoproxyMode == AutoproxyMode.Front)
|
if (settings.AutoproxyMode == AutoproxyMode.Front)
|
||||||
{
|
{
|
||||||
await ctx.Reply($"{Emojis.Note} Autoproxy is already set to front mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
|
await ctx.Reply($"{Emojis.Note} Autoproxy is already set to front mode in this server. If you want to disable autoproxying, use `pk;autoproxy off`.");
|
||||||
}
|
}
|
||||||
@ -75,11 +79,13 @@ public class Autoproxy
|
|||||||
{
|
{
|
||||||
ctx.CheckOwnMember(member);
|
ctx.CheckOwnMember(member);
|
||||||
|
|
||||||
|
// todo: why does this not throw an error if the member is already set
|
||||||
|
|
||||||
await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id);
|
await UpdateAutoproxy(ctx, AutoproxyMode.Member, member.Id);
|
||||||
await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.NameFor(ctx)}** in this server.");
|
await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.NameFor(ctx)}** in this server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Embed> CreateAutoproxyStatusEmbed(Context ctx)
|
private async Task<Embed> CreateAutoproxyStatusEmbed(Context ctx, AutoproxySettings settings)
|
||||||
{
|
{
|
||||||
var commandList = "**pk;autoproxy latch** - Autoproxies as last-proxied member"
|
var commandList = "**pk;autoproxy latch** - Autoproxies as last-proxied member"
|
||||||
+ "\n**pk;autoproxy front** - Autoproxies as current (first) fronter"
|
+ "\n**pk;autoproxy front** - Autoproxies as current (first) fronter"
|
||||||
@ -88,14 +94,16 @@ public class Autoproxy
|
|||||||
.Title($"Current autoproxy status (for {ctx.Guild.Name.EscapeMarkdown()})");
|
.Title($"Current autoproxy status (for {ctx.Guild.Name.EscapeMarkdown()})");
|
||||||
|
|
||||||
var fronters = ctx.MessageContext.LastSwitchMembers;
|
var fronters = ctx.MessageContext.LastSwitchMembers;
|
||||||
var relevantMember = ctx.MessageContext.AutoproxyMode switch
|
var relevantMember = settings.AutoproxyMode switch
|
||||||
{
|
{
|
||||||
AutoproxyMode.Front => fronters.Length > 0 ? await ctx.Repository.GetMember(fronters[0]) : null,
|
AutoproxyMode.Front => fronters.Length > 0 ? await ctx.Repository.GetMember(fronters[0]) : null,
|
||||||
AutoproxyMode.Member when ctx.MessageContext.AutoproxyMember.HasValue => await ctx.Repository.GetMember(ctx.MessageContext.AutoproxyMember.Value),
|
AutoproxyMode.Member when settings.AutoproxyMember.HasValue => await ctx.Repository.GetMember(settings.AutoproxyMember.Value),
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (ctx.MessageContext.AutoproxyMode)
|
Console.WriteLine(settings.AutoproxyMode);
|
||||||
|
|
||||||
|
switch (settings.AutoproxyMode)
|
||||||
{
|
{
|
||||||
case AutoproxyMode.Off:
|
case AutoproxyMode.Off:
|
||||||
eb.Description($"Autoproxy is currently **off** in this server. To enable it, use one of the following commands:\n{commandList}");
|
eb.Description($"Autoproxy is currently **off** in this server. To enable it, use one of the following commands:\n{commandList}");
|
||||||
@ -136,9 +144,7 @@ public class Autoproxy
|
|||||||
|
|
||||||
private async Task UpdateAutoproxy(Context ctx, AutoproxyMode autoproxyMode, MemberId? autoproxyMember)
|
private async Task UpdateAutoproxy(Context ctx, AutoproxyMode autoproxyMode, MemberId? autoproxyMember)
|
||||||
{
|
{
|
||||||
await ctx.Repository.GetSystemGuild(ctx.Guild.Id, ctx.System.Id);
|
var patch = new AutoproxyPatch { AutoproxyMode = autoproxyMode, AutoproxyMember = autoproxyMember };
|
||||||
|
await ctx.Repository.UpdateAutoproxy(ctx.System.Id, ctx.Guild.Id, null, patch);
|
||||||
var patch = new SystemGuildPatch { AutoproxyMode = autoproxyMode, AutoproxyMember = autoproxyMember };
|
|
||||||
await ctx.Repository.UpdateSystemGuild(ctx.System.Id, ctx.Guild.Id, patch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -259,11 +259,16 @@ public class Checks
|
|||||||
var context = await ctx.Repository.GetMessageContext(msg.Author.Id, channel.GuildId.Value, msg.ChannelId);
|
var context = await ctx.Repository.GetMessageContext(msg.Author.Id, channel.GuildId.Value, msg.ChannelId);
|
||||||
var members = (await ctx.Repository.GetProxyMembers(msg.Author.Id, channel.GuildId.Value)).ToList();
|
var members = (await ctx.Repository.GetProxyMembers(msg.Author.Id, channel.GuildId.Value)).ToList();
|
||||||
|
|
||||||
|
// for now this is just server
|
||||||
|
var autoproxySettings = await ctx.Repository.GetAutoproxySettings(ctx.System.Id, channel.GuildId.Value, null);
|
||||||
|
|
||||||
|
// todo: match unlatch
|
||||||
|
|
||||||
// Run everything through the checks, catch the ProxyCheckFailedException, and reply with the error message.
|
// Run everything through the checks, catch the ProxyCheckFailedException, and reply with the error message.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_proxy.ShouldProxy(channel, msg, context);
|
_proxy.ShouldProxy(channel, msg, context);
|
||||||
_matcher.TryMatch(context, members, out var match, msg.Content, msg.Attachments.Length > 0,
|
_matcher.TryMatch(context, autoproxySettings, members, out var match, msg.Content, msg.Attachments.Length > 0,
|
||||||
context.AllowAutoproxy);
|
context.AllowAutoproxy);
|
||||||
|
|
||||||
await ctx.Reply("I'm not sure why this message was not proxied, sorry.");
|
await ctx.Reply("I'm not sure why this message was not proxied, sorry.");
|
||||||
|
@ -18,12 +18,12 @@ public class ProxyMatcher
|
|||||||
_clock = clock;
|
_clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryMatch(MessageContext ctx, IReadOnlyCollection<ProxyMember> members, out ProxyMatch match,
|
public bool TryMatch(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection<ProxyMember> members, out ProxyMatch match,
|
||||||
string messageContent,
|
string messageContent,
|
||||||
bool hasAttachments, bool allowAutoproxy)
|
bool hasAttachments, bool allowAutoproxy)
|
||||||
{
|
{
|
||||||
if (TryMatchTags(members, messageContent, hasAttachments, out match)) return true;
|
if (TryMatchTags(members, messageContent, hasAttachments, out match)) return true;
|
||||||
if (allowAutoproxy && TryMatchAutoproxy(ctx, members, messageContent, out match)) return true;
|
if (allowAutoproxy && TryMatchAutoproxy(ctx, settings, members, messageContent, out match)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ public class ProxyMatcher
|
|||||||
return hasAttachments || match.Content.Trim().Length > 0;
|
return hasAttachments || match.Content.Trim().Length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryMatchAutoproxy(MessageContext ctx, IReadOnlyCollection<ProxyMember> members,
|
private bool TryMatchAutoproxy(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection<ProxyMember> members,
|
||||||
string messageContent,
|
string messageContent,
|
||||||
out ProxyMatch match)
|
out ProxyMatch match)
|
||||||
{
|
{
|
||||||
@ -49,41 +49,41 @@ public class ProxyMatcher
|
|||||||
"This message matches none of your proxy tags, and it was not autoproxied because it starts with a backslash (`\\`).");
|
"This message matches none of your proxy tags, and it was not autoproxied because it starts with a backslash (`\\`).");
|
||||||
|
|
||||||
// Find the member we should autoproxy (null if none)
|
// Find the member we should autoproxy (null if none)
|
||||||
var member = ctx.AutoproxyMode switch
|
var member = settings.AutoproxyMode switch
|
||||||
{
|
{
|
||||||
AutoproxyMode.Member when ctx.AutoproxyMember != null =>
|
AutoproxyMode.Member when settings.AutoproxyMember != null =>
|
||||||
members.FirstOrDefault(m => m.Id == ctx.AutoproxyMember),
|
members.FirstOrDefault(m => m.Id == settings.AutoproxyMember),
|
||||||
|
|
||||||
AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 =>
|
AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 =>
|
||||||
members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]),
|
members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]),
|
||||||
|
|
||||||
AutoproxyMode.Latch when ctx.LastMessageMember != null =>
|
AutoproxyMode.Latch when settings.AutoproxyMember != null =>
|
||||||
members.FirstOrDefault(m => m.Id == ctx.LastMessageMember.Value),
|
members.FirstOrDefault(m => m.Id == settings.AutoproxyMember.Value),
|
||||||
|
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
// Throw an error if the member is null, message varies depending on autoproxy mode
|
// Throw an error if the member is null, message varies depending on autoproxy mode
|
||||||
if (member == null)
|
if (member == null)
|
||||||
{
|
{
|
||||||
if (ctx.AutoproxyMode == AutoproxyMode.Front)
|
if (settings.AutoproxyMode == AutoproxyMode.Front)
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"You are using autoproxy front, but no members are currently registered as fronting. Please use `pk;switch <member>` to log a new switch.");
|
"You are using autoproxy front, but no members are currently registered as fronting. Please use `pk;switch <member>` to log a new switch.");
|
||||||
if (ctx.AutoproxyMode == AutoproxyMode.Member)
|
if (settings.AutoproxyMode == AutoproxyMode.Member)
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"You are using member-specific autoproxy with an invalid member. Was this member deleted?");
|
"You are using member-specific autoproxy with an invalid member. Was this member deleted?");
|
||||||
if (ctx.AutoproxyMode == AutoproxyMode.Latch)
|
if (settings.AutoproxyMode == AutoproxyMode.Latch)
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"You are using autoproxy latch, but have not sent any messages yet in this server. Please send a message using proxy tags first.");
|
"You are using autoproxy latch, but have not sent any messages yet in this server. Please send a message using proxy tags first.");
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"This message matches none of your proxy tags and autoproxy is not enabled.");
|
"This message matches none of your proxy tags and autoproxy is not enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)
|
if (settings.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"This member has autoproxy disabled. To enable it, use `pk;m <member> autoproxy on`.");
|
"This member has autoproxy disabled. To enable it, use `pk;m <member> autoproxy on`.");
|
||||||
|
|
||||||
// Moved the IsLatchExpired() check to here, so that an expired latch and a latch without any previous messages throw different errors
|
// Moved the IsLatchExpired() check to here, so that an expired latch and a latch without any previous messages throw different errors
|
||||||
if (ctx.AutoproxyMode == AutoproxyMode.Latch && IsLatchExpired(ctx))
|
if (settings.AutoproxyMode == AutoproxyMode.Latch && IsLatchExpired(ctx, settings))
|
||||||
throw new ProxyService.ProxyChecksFailedException(
|
throw new ProxyService.ProxyChecksFailedException(
|
||||||
"Latch-mode autoproxy has timed out. Please send a new message using proxy tags.");
|
"Latch-mode autoproxy has timed out. Please send a new message using proxy tags.");
|
||||||
|
|
||||||
@ -99,16 +99,14 @@ public class ProxyMatcher
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsLatchExpired(MessageContext ctx)
|
private bool IsLatchExpired(MessageContext ctx, AutoproxySettings settings)
|
||||||
{
|
{
|
||||||
if (ctx.LastMessage == null) return true;
|
|
||||||
if (ctx.LatchTimeout == 0) return false;
|
if (ctx.LatchTimeout == 0) return false;
|
||||||
|
|
||||||
var timeout = ctx.LatchTimeout.HasValue
|
var timeout = ctx.LatchTimeout.HasValue
|
||||||
? Duration.FromSeconds(ctx.LatchTimeout.Value)
|
? Duration.FromSeconds(ctx.LatchTimeout.Value)
|
||||||
: DefaultLatchExpiryTime;
|
: DefaultLatchExpiryTime;
|
||||||
|
|
||||||
var timestamp = DiscordUtils.SnowflakeToInstant(ctx.LastMessage.Value);
|
return _clock.GetCurrentInstant() - settings.LastLatchTimestamp > timeout;
|
||||||
return _clock.GetCurrentInstant() - timestamp > timeout;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,10 +32,11 @@ public class ProxyService
|
|||||||
private readonly ModelRepository _repo;
|
private readonly ModelRepository _repo;
|
||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
private readonly WebhookExecutorService _webhookExecutor;
|
private readonly WebhookExecutorService _webhookExecutor;
|
||||||
|
private readonly NodaTime.IClock _clock;
|
||||||
|
|
||||||
public ProxyService(LogChannelService logChannel, ILogger logger, WebhookExecutorService webhookExecutor,
|
public ProxyService(LogChannelService logChannel, ILogger logger, WebhookExecutorService webhookExecutor,
|
||||||
DispatchService dispatch, IDatabase db, ProxyMatcher matcher, IMetrics metrics, ModelRepository repo,
|
DispatchService dispatch, IDatabase db, ProxyMatcher matcher, IMetrics metrics, ModelRepository repo,
|
||||||
IDiscordCache cache, DiscordApiClient rest, LastMessageCacheService lastMessage)
|
NodaTime.IClock clock, IDiscordCache cache, DiscordApiClient rest, LastMessageCacheService lastMessage)
|
||||||
{
|
{
|
||||||
_logChannel = logChannel;
|
_logChannel = logChannel;
|
||||||
_webhookExecutor = webhookExecutor;
|
_webhookExecutor = webhookExecutor;
|
||||||
@ -47,6 +48,7 @@ public class ProxyService
|
|||||||
_cache = cache;
|
_cache = cache;
|
||||||
_lastMessage = lastMessage;
|
_lastMessage = lastMessage;
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
|
_clock = clock;
|
||||||
_logger = logger.ForContext<ProxyService>();
|
_logger = logger.ForContext<ProxyService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +58,17 @@ public class ProxyService
|
|||||||
if (!ShouldProxy(channel, message, ctx))
|
if (!ShouldProxy(channel, message, ctx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var autoproxySettings = await _repo.GetAutoproxySettings(ctx.SystemId.Value, guild.Id, null);
|
||||||
|
|
||||||
|
if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message))
|
||||||
|
{
|
||||||
|
// "unlatch"
|
||||||
|
await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() {
|
||||||
|
AutoproxyMember = null
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var rootChannel = await _cache.GetRootChannel(message.ChannelId);
|
var rootChannel = await _cache.GetRootChannel(message.ChannelId);
|
||||||
|
|
||||||
List<ProxyMember> members;
|
List<ProxyMember> members;
|
||||||
@ -63,7 +76,7 @@ public class ProxyService
|
|||||||
using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
|
using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
|
||||||
members = (await _repo.GetProxyMembers(message.Author.Id, message.GuildId!.Value)).ToList();
|
members = (await _repo.GetProxyMembers(message.Author.Id, message.GuildId!.Value)).ToList();
|
||||||
|
|
||||||
if (!_matcher.TryMatch(ctx, members, out var match, message.Content, message.Attachments.Length > 0,
|
if (!_matcher.TryMatch(ctx, autoproxySettings, members, out var match, message.Content, message.Attachments.Length > 0,
|
||||||
allowAutoproxy)) return false;
|
allowAutoproxy)) return false;
|
||||||
|
|
||||||
// this is hopefully temporary, so not putting it into a separate method
|
// this is hopefully temporary, so not putting it into a separate method
|
||||||
@ -84,7 +97,7 @@ public class ProxyService
|
|||||||
var allowEmbeds = senderPermissions.HasFlag(PermissionSet.EmbedLinks);
|
var allowEmbeds = senderPermissions.HasFlag(PermissionSet.EmbedLinks);
|
||||||
|
|
||||||
// Everything's in order, we can execute the proxy!
|
// Everything's in order, we can execute the proxy!
|
||||||
await ExecuteProxy(message, ctx, match, allowEveryone, allowEmbeds);
|
await ExecuteProxy(message, ctx, autoproxySettings, match, allowEveryone, allowEmbeds);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +142,7 @@ public class ProxyService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteProxy(Message trigger, MessageContext ctx,
|
private async Task ExecuteProxy(Message trigger, MessageContext ctx, AutoproxySettings autoproxySettings,
|
||||||
ProxyMatch match, bool allowEveryone, bool allowEmbeds)
|
ProxyMatch match, bool allowEveryone, bool allowEmbeds)
|
||||||
{
|
{
|
||||||
// Create reply embed
|
// Create reply embed
|
||||||
@ -171,7 +184,7 @@ public class ProxyService
|
|||||||
Stickers = trigger.StickerItems,
|
Stickers = trigger.StickerItems,
|
||||||
AllowEveryone = allowEveryone
|
AllowEveryone = allowEveryone
|
||||||
});
|
});
|
||||||
await HandleProxyExecutedActions(ctx, trigger, proxyMessage, match);
|
await HandleProxyExecutedActions(ctx, autoproxySettings, trigger, proxyMessage, match);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(string?, string?)> FetchReferencedMessageAuthorInfo(Message trigger, Message referenced)
|
private async Task<(string?, string?)> FetchReferencedMessageAuthorInfo(Message trigger, Message referenced)
|
||||||
@ -290,7 +303,11 @@ public class ProxyService
|
|||||||
private string FixSameNameInner(string name)
|
private string FixSameNameInner(string name)
|
||||||
=> $"{name}\u17b5";
|
=> $"{name}\u17b5";
|
||||||
|
|
||||||
private async Task HandleProxyExecutedActions(MessageContext ctx, Message triggerMessage, Message proxyMessage, ProxyMatch match)
|
public static bool IsUnlatch(Message message)
|
||||||
|
=> message.Content.StartsWith(@"\\") || message.Content.StartsWith("\\\u200b\\");
|
||||||
|
|
||||||
|
private async Task HandleProxyExecutedActions(MessageContext ctx, AutoproxySettings autoproxySettings,
|
||||||
|
Message triggerMessage, Message proxyMessage, ProxyMatch match)
|
||||||
{
|
{
|
||||||
var sentMessage = new PKMessage
|
var sentMessage = new PKMessage
|
||||||
{
|
{
|
||||||
@ -308,6 +325,14 @@ public class ProxyService
|
|||||||
Task LogMessageToChannel() =>
|
Task LogMessageToChannel() =>
|
||||||
_logChannel.LogMessage(ctx, sentMessage, triggerMessage, proxyMessage).AsTask();
|
_logChannel.LogMessage(ctx, sentMessage, triggerMessage, proxyMessage).AsTask();
|
||||||
|
|
||||||
|
Task SaveLatchAutoproxy() => autoproxySettings.AutoproxyMode == AutoproxyMode.Latch
|
||||||
|
? _repo.UpdateAutoproxy(ctx.SystemId.Value, triggerMessage.GuildId, null, new()
|
||||||
|
{
|
||||||
|
AutoproxyMember = match.Member.Id,
|
||||||
|
LastLatchTimestamp = _clock.GetCurrentInstant(),
|
||||||
|
})
|
||||||
|
: Task.CompletedTask;
|
||||||
|
|
||||||
Task DispatchWebhook() => _dispatch.Dispatch(ctx.SystemId.Value, sentMessage);
|
Task DispatchWebhook() => _dispatch.Dispatch(ctx.SystemId.Value, sentMessage);
|
||||||
|
|
||||||
async Task DeleteProxyTriggerMessage()
|
async Task DeleteProxyTriggerMessage()
|
||||||
@ -333,6 +358,7 @@ public class ProxyService
|
|||||||
DeleteProxyTriggerMessage(),
|
DeleteProxyTriggerMessage(),
|
||||||
SaveMessageInDatabase(),
|
SaveMessageInDatabase(),
|
||||||
LogMessageToChannel(),
|
LogMessageToChannel(),
|
||||||
|
SaveLatchAutoproxy(),
|
||||||
DispatchWebhook()
|
DispatchWebhook()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,6 @@ public class MessageContext
|
|||||||
public bool InLogBlacklist { get; }
|
public bool InLogBlacklist { get; }
|
||||||
public bool LogCleanupEnabled { get; }
|
public bool LogCleanupEnabled { get; }
|
||||||
public bool ProxyEnabled { get; }
|
public bool ProxyEnabled { get; }
|
||||||
public AutoproxyMode AutoproxyMode { get; }
|
|
||||||
public MemberId? AutoproxyMember { get; }
|
|
||||||
public ulong? LastMessage { get; }
|
|
||||||
public MemberId? LastMessageMember { get; }
|
|
||||||
public SwitchId? LastSwitch { get; }
|
public SwitchId? LastSwitch { get; }
|
||||||
public MemberId[] LastSwitchMembers { get; } = new MemberId[0];
|
public MemberId[] LastSwitchMembers { get; } = new MemberId[0];
|
||||||
public Instant? LastSwitchTimestamp { get; }
|
public Instant? LastSwitchTimestamp { get; }
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
in_log_blacklist bool,
|
in_log_blacklist bool,
|
||||||
log_cleanup_enabled bool,
|
log_cleanup_enabled bool,
|
||||||
proxy_enabled bool,
|
proxy_enabled bool,
|
||||||
autoproxy_mode int,
|
|
||||||
autoproxy_member int,
|
|
||||||
last_message bigint,
|
|
||||||
last_message_member int,
|
|
||||||
last_switch int,
|
last_switch int,
|
||||||
last_switch_members int[],
|
last_switch_members int[],
|
||||||
last_switch_timestamp timestamp,
|
last_switch_timestamp timestamp,
|
||||||
@ -28,8 +24,7 @@ as $$
|
|||||||
left join system_config on system_config.system = accounts.system
|
left join system_config on system_config.system = accounts.system
|
||||||
left join system_guild on system_guild.system = accounts.system and system_guild.guild = guild_id
|
left join system_guild on system_guild.system = accounts.system and system_guild.guild = guild_id
|
||||||
where accounts.uid = account_id),
|
where accounts.uid = account_id),
|
||||||
guild as (select * from servers where id = guild_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
|
select
|
||||||
system.id as system_id,
|
system.id as system_id,
|
||||||
guild.log_channel,
|
guild.log_channel,
|
||||||
@ -37,10 +32,6 @@ as $$
|
|||||||
(channel_id = any(guild.log_blacklist)) as in_log_blacklist,
|
(channel_id = any(guild.log_blacklist)) as in_log_blacklist,
|
||||||
coalesce(guild.log_cleanup_enabled, false),
|
coalesce(guild.log_cleanup_enabled, false),
|
||||||
coalesce(system_guild.proxy_enabled, true) as proxy_enabled,
|
coalesce(system_guild.proxy_enabled, true) as proxy_enabled,
|
||||||
coalesce(system_guild.autoproxy_mode, 1) as autoproxy_mode,
|
|
||||||
system_guild.autoproxy_member,
|
|
||||||
last_message.mid as last_message,
|
|
||||||
last_message.member as last_message_member,
|
|
||||||
system_last_switch.switch as last_switch,
|
system_last_switch.switch as last_switch,
|
||||||
system_last_switch.members as last_switch_members,
|
system_last_switch.members as last_switch_members,
|
||||||
system_last_switch.timestamp as last_switch_timestamp,
|
system_last_switch.timestamp as last_switch_timestamp,
|
||||||
@ -55,7 +46,6 @@ as $$
|
|||||||
from (select 1) as _placeholder
|
from (select 1) as _placeholder
|
||||||
left join system on true
|
left join system on true
|
||||||
left join guild on true
|
left join guild on true
|
||||||
left join last_message on true
|
|
||||||
left join system_last_switch on system_last_switch.system = system.id
|
left join system_last_switch on system_last_switch.system = system.id
|
||||||
left join system_guild on system_guild.system = system.id and system_guild.guild = guild_id
|
left join system_guild on system_guild.system = system.id and system_guild.guild = guild_id
|
||||||
$$ language sql stable rows 1;
|
$$ language sql stable rows 1;
|
||||||
|
36
PluralKit.Core/Database/Migrations/27.sql
Normal file
36
PluralKit.Core/Database/Migrations/27.sql
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
-- schema version 27
|
||||||
|
-- autoproxy locations
|
||||||
|
|
||||||
|
-- mode pseudo-enum: (copied from 3.sql)
|
||||||
|
-- 1 = autoproxy off
|
||||||
|
-- 2 = front mode (first fronter)
|
||||||
|
-- 3 = latch mode (last proxyer)
|
||||||
|
-- 4 = member mode (specific member)
|
||||||
|
|
||||||
|
create table autoproxy (
|
||||||
|
system int references systems(id) on delete cascade,
|
||||||
|
channel_id bigint,
|
||||||
|
guild_id bigint,
|
||||||
|
autoproxy_mode int check (mode in (1, 2, 3, 4)) not null default 1,
|
||||||
|
autoproxy_member int references members(id) on delete set null,
|
||||||
|
last_latch_timestamp timestamp,
|
||||||
|
check (
|
||||||
|
(channel_id = 0 and guild_id = 0)
|
||||||
|
or (channel_id != 0 and guild_id = 0)
|
||||||
|
or (channel_id = 0 and guild_id != 0)
|
||||||
|
),
|
||||||
|
primary key (system, channel_id, guild_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into autoproxy select
|
||||||
|
system,
|
||||||
|
0 as channel_id,
|
||||||
|
guild as guild_id,
|
||||||
|
autoproxy_mode,
|
||||||
|
autoproxy_member
|
||||||
|
from system_guild;
|
||||||
|
|
||||||
|
alter table system_guild drop column autoproxy_mode;
|
||||||
|
alter table system_guild drop column autoproxy_member;
|
||||||
|
|
||||||
|
update info set schema_version = 27;
|
@ -0,0 +1,35 @@
|
|||||||
|
using Dapper;
|
||||||
|
|
||||||
|
using SqlKata;
|
||||||
|
|
||||||
|
namespace PluralKit.Core;
|
||||||
|
|
||||||
|
public partial class ModelRepository
|
||||||
|
{
|
||||||
|
public async Task UpdateAutoproxy(SystemId system, ulong? guildId, ulong? channelId, AutoproxyPatch patch)
|
||||||
|
{
|
||||||
|
var locationStr = guildId != null ? "guild" : (channelId != null ? "channel" : "global");
|
||||||
|
_logger.Information("Updated autoproxy for {SystemId} in location {location}: {@AutoproxyPatch}", system, locationStr, patch);
|
||||||
|
|
||||||
|
var query = patch.Apply(new Query("autoproxy")
|
||||||
|
.Where("system", system)
|
||||||
|
.Where("guild_id", guildId ?? 0)
|
||||||
|
.Where("channel_id", channelId ?? 0)
|
||||||
|
);
|
||||||
|
_ = _dispatch.Dispatch(system, guildId, channelId, patch);
|
||||||
|
await _db.ExecuteQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: this might break with differently scoped autoproxy
|
||||||
|
public async Task<AutoproxySettings> GetAutoproxySettings(SystemId system, ulong? guildId, ulong? channelId)
|
||||||
|
=> await _db.QueryFirst<AutoproxySettings>(new Query("autoproxy").AsInsert(new {
|
||||||
|
system = system,
|
||||||
|
guild_id = guildId ?? 0,
|
||||||
|
channel_id = channelId ?? 0,
|
||||||
|
})
|
||||||
|
.Where("system", system)
|
||||||
|
.Where("guild_id", guildId ?? 0)
|
||||||
|
.Where("channel_id", channelId ?? 0),
|
||||||
|
"on conflict (system, guild_id, channel_id) do update set system = $1 returning *"
|
||||||
|
);
|
||||||
|
}
|
@ -9,7 +9,7 @@ namespace PluralKit.Core;
|
|||||||
internal class DatabaseMigrator
|
internal class DatabaseMigrator
|
||||||
{
|
{
|
||||||
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
|
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
|
||||||
private const int TargetSchemaVersion = 26;
|
private const int TargetSchemaVersion = 27;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public DatabaseMigrator(ILogger logger)
|
public DatabaseMigrator(ILogger logger)
|
||||||
|
@ -38,6 +38,12 @@ public class DispatchService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Dispatch(SystemId systemId, ulong? guildId, ulong? channelId, AutoproxyPatch patch)
|
||||||
|
{
|
||||||
|
// todo
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Dispatch(SystemId systemId, UpdateDispatchData data)
|
public async Task Dispatch(SystemId systemId, UpdateDispatchData data)
|
||||||
{
|
{
|
||||||
if (data.EventData != null && data.EventData.Count == 0)
|
if (data.EventData != null && data.EventData.Count == 0)
|
||||||
@ -159,18 +165,11 @@ public class DispatchService
|
|||||||
if (system.WebhookUrl == null)
|
if (system.WebhookUrl == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string memberRef = null;
|
|
||||||
if (patch.AutoproxyMember.Value != null)
|
|
||||||
{
|
|
||||||
var member = await repo.GetMember(patch.AutoproxyMember.Value.Value);
|
|
||||||
memberRef = member.Uuid.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = new UpdateDispatchData();
|
var data = new UpdateDispatchData();
|
||||||
data.Event = DispatchEvent.UPDATE_SYSTEM_GUILD;
|
data.Event = DispatchEvent.UPDATE_SYSTEM_GUILD;
|
||||||
data.SigningToken = system.WebhookToken;
|
data.SigningToken = system.WebhookToken;
|
||||||
data.SystemId = system.Uuid.ToString();
|
data.SystemId = system.Uuid.ToString();
|
||||||
data.EventData = patch.ToJson(memberRef, guild_id);
|
data.EventData = patch.ToJson(guild_id);
|
||||||
|
|
||||||
_logger.Debug("Dispatching webhook for system {SystemId} in guild {GuildId}", system.Id, guild_id);
|
_logger.Debug("Dispatching webhook for system {SystemId} in guild {GuildId}", system.Id, guild_id);
|
||||||
await DoPostRequest(system.Id, system.WebhookUrl, data.GetPayloadBody());
|
await DoPostRequest(system.Id, system.WebhookUrl, data.GetPayloadBody());
|
||||||
|
59
PluralKit.Core/Models/Autoproxy.cs
Normal file
59
PluralKit.Core/Models/Autoproxy.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
|
namespace PluralKit.Core;
|
||||||
|
|
||||||
|
public enum AutoproxyMode
|
||||||
|
{
|
||||||
|
Off = 1,
|
||||||
|
Front = 2,
|
||||||
|
Latch = 3,
|
||||||
|
Member = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AutoproxySettings
|
||||||
|
{
|
||||||
|
public AutoproxyMode AutoproxyMode { get; }
|
||||||
|
public MemberId? AutoproxyMember { get; }
|
||||||
|
public Instant LastLatchTimestamp { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AutoproxyExt
|
||||||
|
{
|
||||||
|
public static JObject ToJson(this AutoproxySettings settings, string? memberHid = null)
|
||||||
|
{
|
||||||
|
var o = new JObject();
|
||||||
|
|
||||||
|
// tbd
|
||||||
|
o.Add("autoproxy_mode", settings.AutoproxyMode.ToString().ToLower());
|
||||||
|
o.Add("autoproxy_member", memberHid);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (AutoproxyMode?, ValidationError?) ParseAutoproxyMode(this JToken o)
|
||||||
|
{
|
||||||
|
if (o.Type == JTokenType.Null)
|
||||||
|
return (AutoproxyMode.Off, null);
|
||||||
|
if (o.Type != JTokenType.String)
|
||||||
|
return (null, new ValidationError("autoproxy_mode"));
|
||||||
|
|
||||||
|
var value = o.Value<string>();
|
||||||
|
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "off":
|
||||||
|
return (AutoproxyMode.Off, null);
|
||||||
|
case "front":
|
||||||
|
return (AutoproxyMode.Front, null);
|
||||||
|
case "latch":
|
||||||
|
return (AutoproxyMode.Latch, null);
|
||||||
|
case "member":
|
||||||
|
return (AutoproxyMode.Member, null);
|
||||||
|
default:
|
||||||
|
return (null,
|
||||||
|
new ValidationError("autoproxy_mode", $"Value '{value}' is not a valid autoproxy mode."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
PluralKit.Core/Models/Patch/AutoproxyPatch.cs
Normal file
21
PluralKit.Core/Models/Patch/AutoproxyPatch.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
|
using SqlKata;
|
||||||
|
|
||||||
|
namespace PluralKit.Core;
|
||||||
|
|
||||||
|
public class AutoproxyPatch : PatchObject
|
||||||
|
{
|
||||||
|
public Partial<AutoproxyMode> AutoproxyMode { get; set; }
|
||||||
|
public Partial<MemberId?> AutoproxyMember { get; set; }
|
||||||
|
|
||||||
|
public Partial<Instant> LastLatchTimestamp { get; set; }
|
||||||
|
|
||||||
|
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
|
||||||
|
.With("autoproxy_mode", AutoproxyMode)
|
||||||
|
.With("autoproxy_member", AutoproxyMember)
|
||||||
|
.With("last_latch_timestamp", LastLatchTimestamp)
|
||||||
|
);
|
||||||
|
}
|
@ -9,15 +9,11 @@ namespace PluralKit.Core;
|
|||||||
public class SystemGuildPatch: PatchObject
|
public class SystemGuildPatch: PatchObject
|
||||||
{
|
{
|
||||||
public Partial<bool> ProxyEnabled { get; set; }
|
public Partial<bool> ProxyEnabled { get; set; }
|
||||||
public Partial<AutoproxyMode> AutoproxyMode { get; set; }
|
|
||||||
public Partial<MemberId?> AutoproxyMember { get; set; }
|
|
||||||
public Partial<string?> Tag { get; set; }
|
public Partial<string?> Tag { get; set; }
|
||||||
public Partial<bool?> TagEnabled { get; set; }
|
public Partial<bool?> TagEnabled { get; set; }
|
||||||
|
|
||||||
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
|
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
|
||||||
.With("proxy_enabled", ProxyEnabled)
|
.With("proxy_enabled", ProxyEnabled)
|
||||||
.With("autoproxy_mode", AutoproxyMode)
|
|
||||||
.With("autoproxy_member", AutoproxyMember)
|
|
||||||
.With("tag", Tag)
|
.With("tag", Tag)
|
||||||
.With("tag_enabled", TagEnabled)
|
.With("tag_enabled", TagEnabled)
|
||||||
);
|
);
|
||||||
@ -29,24 +25,13 @@ public class SystemGuildPatch: PatchObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
public static SystemGuildPatch FromJson(JObject o, MemberId? memberId)
|
public static SystemGuildPatch FromJson(JObject o)
|
||||||
{
|
{
|
||||||
var patch = new SystemGuildPatch();
|
var patch = new SystemGuildPatch();
|
||||||
|
|
||||||
if (o.ContainsKey("proxying_enabled") && o["proxying_enabled"].Type != JTokenType.Null)
|
if (o.ContainsKey("proxying_enabled") && o["proxying_enabled"].Type != JTokenType.Null)
|
||||||
patch.ProxyEnabled = o.Value<bool>("proxying_enabled");
|
patch.ProxyEnabled = o.Value<bool>("proxying_enabled");
|
||||||
|
|
||||||
if (o.ContainsKey("autoproxy_mode"))
|
|
||||||
{
|
|
||||||
var (val, err) = o["autoproxy_mode"].ParseAutoproxyMode();
|
|
||||||
if (err != null)
|
|
||||||
patch.Errors.Add(err);
|
|
||||||
else
|
|
||||||
patch.AutoproxyMode = val.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.AutoproxyMember = memberId;
|
|
||||||
|
|
||||||
if (o.ContainsKey("tag"))
|
if (o.ContainsKey("tag"))
|
||||||
patch.Tag = o.Value<string>("tag").NullIfEmpty();
|
patch.Tag = o.Value<string>("tag").NullIfEmpty();
|
||||||
|
|
||||||
@ -56,7 +41,7 @@ public class SystemGuildPatch: PatchObject
|
|||||||
return patch;
|
return patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JObject ToJson(string memberRef, ulong guild_id)
|
public JObject ToJson(ulong guild_id)
|
||||||
{
|
{
|
||||||
var o = new JObject();
|
var o = new JObject();
|
||||||
|
|
||||||
@ -65,12 +50,6 @@ public class SystemGuildPatch: PatchObject
|
|||||||
if (ProxyEnabled.IsPresent)
|
if (ProxyEnabled.IsPresent)
|
||||||
o.Add("proxying_enabled", ProxyEnabled.Value);
|
o.Add("proxying_enabled", ProxyEnabled.Value);
|
||||||
|
|
||||||
if (AutoproxyMode.IsPresent)
|
|
||||||
o.Add("autoproxy_mode", AutoproxyMode.Value.ToString().ToLower());
|
|
||||||
|
|
||||||
if (AutoproxyMember.IsPresent)
|
|
||||||
o.Add("autoproxy_member", memberRef);
|
|
||||||
|
|
||||||
if (Tag.IsPresent)
|
if (Tag.IsPresent)
|
||||||
o.Add("tag", Tag.Value);
|
o.Add("tag", Tag.Value);
|
||||||
|
|
||||||
|
@ -1,68 +1,26 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace PluralKit.Core;
|
namespace PluralKit.Core;
|
||||||
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public enum AutoproxyMode
|
|
||||||
{
|
|
||||||
Off = 1,
|
|
||||||
Front = 2,
|
|
||||||
Latch = 3,
|
|
||||||
Member = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SystemGuildSettings
|
public class SystemGuildSettings
|
||||||
{
|
{
|
||||||
public ulong Guild { get; }
|
public ulong Guild { get; }
|
||||||
public SystemId System { get; }
|
public SystemId System { get; }
|
||||||
public bool ProxyEnabled { get; } = true;
|
public bool ProxyEnabled { get; } = true;
|
||||||
|
|
||||||
public AutoproxyMode AutoproxyMode { get; } = AutoproxyMode.Off;
|
|
||||||
public MemberId? AutoproxyMember { get; }
|
|
||||||
|
|
||||||
public string? Tag { get; }
|
public string? Tag { get; }
|
||||||
public bool TagEnabled { get; }
|
public bool TagEnabled { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SystemGuildExt
|
public static class SystemGuildExt
|
||||||
{
|
{
|
||||||
public static JObject ToJson(this SystemGuildSettings settings, string? memberHid = null)
|
public static JObject ToJson(this SystemGuildSettings settings)
|
||||||
{
|
{
|
||||||
var o = new JObject();
|
var o = new JObject();
|
||||||
|
|
||||||
o.Add("proxying_enabled", settings.ProxyEnabled);
|
o.Add("proxying_enabled", settings.ProxyEnabled);
|
||||||
o.Add("autoproxy_mode", settings.AutoproxyMode.ToString().ToLower());
|
|
||||||
o.Add("autoproxy_member", memberHid);
|
|
||||||
o.Add("tag", settings.Tag);
|
o.Add("tag", settings.Tag);
|
||||||
o.Add("tag_enabled", settings.TagEnabled);
|
o.Add("tag_enabled", settings.TagEnabled);
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (AutoproxyMode?, ValidationError?) ParseAutoproxyMode(this JToken o)
|
|
||||||
{
|
|
||||||
if (o.Type == JTokenType.Null)
|
|
||||||
return (AutoproxyMode.Off, null);
|
|
||||||
if (o.Type != JTokenType.String)
|
|
||||||
return (null, new ValidationError("autoproxy_mode"));
|
|
||||||
|
|
||||||
var value = o.Value<string>();
|
|
||||||
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case "off":
|
|
||||||
return (AutoproxyMode.Off, null);
|
|
||||||
case "front":
|
|
||||||
return (AutoproxyMode.Front, null);
|
|
||||||
case "latch":
|
|
||||||
return (AutoproxyMode.Latch, null);
|
|
||||||
case "member":
|
|
||||||
return (AutoproxyMode.Member, null);
|
|
||||||
default:
|
|
||||||
return (null,
|
|
||||||
new ValidationError("autoproxy_mode", $"Value '{value}' is not a valid autoproxy mode."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -120,11 +120,10 @@ Every PluralKit entity has two IDs: a short (5-character) ID and a longer UUID.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
|guild_id|snowflake|only sent if the guild ID isn't already known (in dispatch payloads)|
|
|guild_id|snowflake|only sent if the guild ID isn't already known (in dispatch payloads)|
|
||||||
|proxying_enabled|boolean||
|
|proxying_enabled|boolean||
|
||||||
|autoproxy_mode|autoproxy mode enum||
|
|
||||||
|autoproxy_member|?string|must be set if autoproxy_mode is `member`|
|
|
||||||
|tag|?string|79-character limit|
|
|tag|?string|79-character limit|
|
||||||
|tag_enabled|boolean||
|
|tag_enabled|boolean||
|
||||||
|
|
||||||
|
<!--
|
||||||
#### Autoproxy mode enum
|
#### Autoproxy mode enum
|
||||||
|
|
||||||
|key|description|
|
|key|description|
|
||||||
@ -133,6 +132,7 @@ Every PluralKit entity has two IDs: a short (5-character) ID and a longer UUID.
|
|||||||
|front|autoproxy is set to the first member in the current fronters list, or disabled if the current switch contains no members|
|
|front|autoproxy is set to the first member in the current fronters list, or disabled if the current switch contains no members|
|
||||||
|latch|autoproxy is set to the last member who sent a proxied message in the server|
|
|latch|autoproxy is set to the last member who sent a proxied message in the server|
|
||||||
|member|autoproxy is set to a specific member (see `autoproxy_member` key)|
|
|member|autoproxy is set to a specific member (see `autoproxy_member` key)|
|
||||||
|
-->
|
||||||
|
|
||||||
### Member guild settings model
|
### Member guild settings model
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user