feat(api): add autoproxy endpoints

This commit is contained in:
spiral 2022-06-02 13:32:31 -04:00
parent 67ce371e7e
commit c87979ef03
No known key found for this signature in database
GPG Key ID: 244A11E4B0BCF40E
6 changed files with 152 additions and 6 deletions

View File

@ -0,0 +1,77 @@
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using PluralKit.Core;
namespace PluralKit.API;
[ApiController]
[Route("v2")]
public class AutoproxyControllerV2: PKControllerBase
{
public AutoproxyControllerV2(IServiceProvider svc) : base(svc) { }
// asp.net why
[HttpGet("systems/{systemRef}/autoproxy")]
public Task<IActionResult> GetWrapper([FromRoute] string systemRef, [FromQuery] ulong? guild_id, [FromQuery] ulong? channel_id)
=> Entrypoint(systemRef, guild_id, channel_id, null);
[HttpPatch("systems/{systemRef}/autoproxy")]
public Task<IActionResult> PatchWrapper([FromRoute] string systemRef, [FromQuery] ulong? guild_id, [FromQuery] ulong? channel_id, [FromBody] JObject? data)
=> Entrypoint(systemRef, guild_id, channel_id, data);
public async Task<IActionResult> Entrypoint(string systemRef, ulong? guild_id, ulong? channel_id, JObject? data)
{
var system = await ResolveSystem(systemRef);
if (ContextFor(system) != LookupContext.ByOwner)
throw Errors.GenericMissingPermissions;
if (guild_id == null || channel_id != null)
throw Errors.Unimplemented;
var settings = await _repo.GetAutoproxySettings(system.Id, guild_id, channel_id);
if (settings == null)
return NotFound();
if (HttpContext.Request.Method == "GET")
return await Get(settings);
else if (HttpContext.Request.Method == "PATCH")
return await Patch(system, guild_id, channel_id, data, settings);
else return StatusCode(415);
}
private async Task<IActionResult> Get(AutoproxySettings settings)
{
string hid = null;
if (settings.AutoproxyMember != null)
hid = (await _repo.GetMember(settings.AutoproxyMember.Value))?.Hid;
return Ok(settings.ToJson(hid));
}
private async Task<IActionResult> Patch(PKSystem system, ulong? guildId, ulong? channelId, JObject data, AutoproxySettings oldData)
{
var updateMember = data.ContainsKey("autoproxy_member");
PKMember? member = null;
if (updateMember)
member = await ResolveMember(data.Value<string>("autoproxy_member"));
var patch = AutoproxyPatch.FromJson(data, member?.Id);
patch.AssertIsValid();
if (updateMember && member == null)
patch.Errors.Add(new("autoproxy_member", "Member not found."));
if (updateMember && ((patch.AutoproxyMode.IsPresent && patch.AutoproxyMode.Value == AutoproxyMode.Latch) || oldData.AutoproxyMode == AutoproxyMode.Latch))
patch.Errors.Add(new("autoproxy_member", "Cannot update autoproxy member if autoproxy mode is set to latch"));
if (patch.Errors.Count > 0)
throw new ModelParseError(patch.Errors);
var res = await _repo.UpdateAutoproxy(system.Id, guildId, channelId, patch);
if (!updateMember && oldData.AutoproxyMember != null)
member = await _repo.GetMember(oldData.AutoproxyMember.Value);
return Ok(res.ToJson(member?.Hid));
}
}

View File

@ -6,7 +6,7 @@ namespace PluralKit.Core;
public partial class ModelRepository
{
public async Task UpdateAutoproxy(SystemId system, ulong? guildId, ulong? channelId, AutoproxyPatch patch)
public Task<AutoproxySettings> 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);
@ -17,7 +17,7 @@ public partial class ModelRepository
.Where("channel_id", channelId ?? 0)
);
_ = _dispatch.Dispatch(system, guildId, channelId, patch);
await _db.ExecuteQuery(query);
return _db.QueryFirst<AutoproxySettings>(query, "returning *");
}
// todo: this might break with differently scoped autoproxy

View File

@ -16,7 +16,7 @@ public class AutoproxySettings
{
public AutoproxyMode AutoproxyMode { get; }
public MemberId? AutoproxyMember { get; }
public Instant LastLatchTimestamp { get; }
public Instant? LastLatchTimestamp { get; }
}
public static class AutoproxyExt
@ -27,7 +27,8 @@ public static class AutoproxyExt
// tbd
o.Add("autoproxy_mode", settings.AutoproxyMode.ToString().ToLower());
o.Add("autoproxy_member", memberHid);
o.Add("autoproxy_member", settings.AutoproxyMode == AutoproxyMode.Front ? null : memberHid);
o.Add("last_latch_timestamp", settings.LastLatchTimestamp?.FormatExport());
return o;
}

View File

@ -1,3 +1,5 @@
using Newtonsoft.Json.Linq;
using NodaTime;
using SqlKata;
@ -16,4 +18,30 @@ public class AutoproxyPatch: PatchObject
.With("autoproxy_member", AutoproxyMember)
.With("last_latch_timestamp", LastLatchTimestamp)
);
public new void AssertIsValid()
{
// this is checked in FromJson
// not really the best way to do this, maybe fix at some point?
if ((int?)AutoproxyMode.Value == -1)
Errors.Add(new("autoproxy_mode"));
}
public static AutoproxyPatch FromJson(JObject o, MemberId? autoproxyMember = null)
{
var p = new AutoproxyPatch();
if (o.ContainsKey("autoproxy_mode"))
{
var (autoproxyMode, error) = o.Value<JToken>("autoproxy_mode").ParseAutoproxyMode();
if (error != null)
p.AutoproxyMode = Partial<AutoproxyMode>.Present((AutoproxyMode)(-1));
else
p.AutoproxyMode = autoproxyMode.Value;
}
p.AutoproxyMember = autoproxyMember ?? Partial<MemberId?>.Absent;
return p;
}
}

View File

@ -60,6 +60,40 @@ Takes a partial [system guild settings](/api/models#system-guild-settings-model)
Returns a [system guild settings](/api/models#system-guild-settings-model) object on success.
### Get System Autoproxy Settings
GET `/systems/@me/autoproxy`
Query String Parameters
|name|type|
|---|---|
|guild_id?|snowflake|
|channel_id?|snowflake|
Returns an [autoproxy settings](/api/models/#autoproxy-settings-model) object on success.
::: warning
Currently, only autoproxy with `guild_id` is supported. The API will return an error message if you specify `channel_id`, or do not specify a `guild_id`.
:::
### Update System Autoproxy Settings
PATCH `/systems/@me/autoproxy`
Query String Parameters
|name|type|
|---|---|
|guild_id?|snowflake|
|channel_id?|snowflake|
Takes a partial [autoproxy settings](/api/models/#autoproxy-settings-model) object.
Returns an [autoproxy settings](/api/models/#autoproxy-settings-model) object on success.
::: warning
Currently, only autoproxy with `guild_id` is supported. The API will return an error message if you specify `channel_id`, or do not specify a `guild_id`.
:::
---
## Members

View File

@ -124,7 +124,14 @@ Every PluralKit entity has two IDs: a short (5-character) ID and a longer UUID.
|tag|?string|79-character limit|
|tag_enabled|boolean||
<!--
### Autoproxy settings model
|key|type|notes|
|---|---|---|
|autoproxy_mode|[autoproxy mode](#autoproxy-mode-enum)||
|autoproxy_member|?member id|must be `null` if autoproxy_mode is set to `front`|
|last_latch_timestamp|?datetime|read-only|
#### Autoproxy mode enum
|key|description|
@ -133,7 +140,6 @@ 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|
|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 guild settings model