mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-08 06:47:56 +00:00
feat: rewrite database schema for localized autoproxy
This commit is contained in:
parent
ca108813b7
commit
982812333b
16 changed files with 245 additions and 188 deletions
|
|
@ -15,10 +15,6 @@ public class MessageContext
|
|||
public bool InLogBlacklist { get; }
|
||||
public bool LogCleanupEnabled { 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 MemberId[] LastSwitchMembers { get; } = new MemberId[0];
|
||||
public Instant? LastSwitchTimestamp { get; }
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@
|
|||
in_log_blacklist bool,
|
||||
log_cleanup_enabled bool,
|
||||
proxy_enabled bool,
|
||||
autoproxy_mode int,
|
||||
autoproxy_member int,
|
||||
last_message bigint,
|
||||
last_message_member int,
|
||||
last_switch int,
|
||||
last_switch_members int[],
|
||||
last_switch_timestamp timestamp,
|
||||
|
|
@ -28,8 +24,7 @@ as $$
|
|||
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
|
||||
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)
|
||||
guild as (select * from servers where id = guild_id)
|
||||
select
|
||||
system.id as system_id,
|
||||
guild.log_channel,
|
||||
|
|
@ -37,10 +32,6 @@ as $$
|
|||
(channel_id = any(guild.log_blacklist)) as in_log_blacklist,
|
||||
coalesce(guild.log_cleanup_enabled, false),
|
||||
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.members as last_switch_members,
|
||||
system_last_switch.timestamp as last_switch_timestamp,
|
||||
|
|
@ -55,7 +46,6 @@ as $$
|
|||
from (select 1) as _placeholder
|
||||
left join system 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_guild on system_guild.system = system.id and system_guild.guild = guild_id
|
||||
$$ 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
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
if (data.EventData != null && data.EventData.Count == 0)
|
||||
|
|
@ -159,18 +165,11 @@ public class DispatchService
|
|||
if (system.WebhookUrl == null)
|
||||
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();
|
||||
data.Event = DispatchEvent.UPDATE_SYSTEM_GUILD;
|
||||
data.SigningToken = system.WebhookToken;
|
||||
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);
|
||||
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 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<bool?> TagEnabled { get; set; }
|
||||
|
||||
public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper
|
||||
.With("proxy_enabled", ProxyEnabled)
|
||||
.With("autoproxy_mode", AutoproxyMode)
|
||||
.With("autoproxy_member", AutoproxyMember)
|
||||
.With("tag", Tag)
|
||||
.With("tag_enabled", TagEnabled)
|
||||
);
|
||||
|
|
@ -29,24 +25,13 @@ public class SystemGuildPatch: PatchObject
|
|||
}
|
||||
|
||||
#nullable disable
|
||||
public static SystemGuildPatch FromJson(JObject o, MemberId? memberId)
|
||||
public static SystemGuildPatch FromJson(JObject o)
|
||||
{
|
||||
var patch = new SystemGuildPatch();
|
||||
|
||||
if (o.ContainsKey("proxying_enabled") && o["proxying_enabled"].Type != JTokenType.Null)
|
||||
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"))
|
||||
patch.Tag = o.Value<string>("tag").NullIfEmpty();
|
||||
|
||||
|
|
@ -56,7 +41,7 @@ public class SystemGuildPatch: PatchObject
|
|||
return patch;
|
||||
}
|
||||
|
||||
public JObject ToJson(string memberRef, ulong guild_id)
|
||||
public JObject ToJson(ulong guild_id)
|
||||
{
|
||||
var o = new JObject();
|
||||
|
||||
|
|
@ -65,12 +50,6 @@ public class SystemGuildPatch: PatchObject
|
|||
if (ProxyEnabled.IsPresent)
|
||||
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)
|
||||
o.Add("tag", Tag.Value);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,68 +1,26 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace PluralKit.Core;
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum AutoproxyMode
|
||||
{
|
||||
Off = 1,
|
||||
Front = 2,
|
||||
Latch = 3,
|
||||
Member = 4
|
||||
}
|
||||
|
||||
public class SystemGuildSettings
|
||||
{
|
||||
public ulong Guild { get; }
|
||||
public SystemId System { get; }
|
||||
public bool ProxyEnabled { get; } = true;
|
||||
|
||||
public AutoproxyMode AutoproxyMode { get; } = AutoproxyMode.Off;
|
||||
public MemberId? AutoproxyMember { get; }
|
||||
|
||||
public string? Tag { get; }
|
||||
public bool TagEnabled { get; }
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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_enabled", settings.TagEnabled);
|
||||
|
||||
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."));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue