feat(apiv2): guild endpoints
This commit is contained in:
parent
eb05cbf76c
commit
f602f22a3d
@ -17,40 +17,119 @@ namespace PluralKit.API
|
||||
public GuildControllerV2(IServiceProvider svc) : base(svc) { }
|
||||
|
||||
|
||||
[HttpGet("systems/{system}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> SystemGuildGet(string system, ulong guild_id)
|
||||
[HttpGet("systems/@me/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> SystemGuildGet(ulong guild_id)
|
||||
{
|
||||
return new ObjectResult("Unimplemented")
|
||||
{
|
||||
StatusCode = 501
|
||||
};
|
||||
var system = await ResolveSystem("@me");
|
||||
var settings = await _repo.GetSystemGuild(guild_id, system.Id, defaultInsert: false);
|
||||
if (settings == null)
|
||||
throw APIErrors.SystemGuildNotFound;
|
||||
|
||||
PKMember member = null;
|
||||
if (settings.AutoproxyMember != null)
|
||||
member = await _repo.GetMember(settings.AutoproxyMember.Value);
|
||||
|
||||
return Ok(settings.ToJson(member?.Hid));
|
||||
}
|
||||
|
||||
[HttpPatch("systems/{system}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> SystemGuildPatch(string system, ulong guild_id, [FromBody] JObject data)
|
||||
[HttpPatch("systems/@me/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> DoSystemGuildPatch(ulong guild_id, [FromBody] JObject data)
|
||||
{
|
||||
return new ObjectResult("Unimplemented")
|
||||
var system = await ResolveSystem("@me");
|
||||
var settings = await _repo.GetSystemGuild(guild_id, system.Id, defaultInsert: false);
|
||||
if (settings == null)
|
||||
throw APIErrors.SystemGuildNotFound;
|
||||
|
||||
MemberId? memberId = null;
|
||||
if (data.ContainsKey("autoproxy_member"))
|
||||
{
|
||||
StatusCode = 501
|
||||
};
|
||||
if (data["autoproxy_member"].Type != JTokenType.Null)
|
||||
{
|
||||
var member = await ResolveMember(data.Value<string>("autoproxy_member"));
|
||||
if (member == null)
|
||||
throw APIErrors.MemberNotFound;
|
||||
|
||||
memberId = member.Id;
|
||||
}
|
||||
}
|
||||
else
|
||||
memberId = settings.AutoproxyMember;
|
||||
|
||||
SystemGuildPatch patch = null;
|
||||
try
|
||||
{
|
||||
patch = SystemGuildPatch.FromJson(data, memberId);
|
||||
patch.AssertIsValid();
|
||||
}
|
||||
catch (ValidationError e)
|
||||
{
|
||||
// todo
|
||||
return BadRequest(e.Message);
|
||||
}
|
||||
|
||||
// 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 APIErrors.MissingAutoproxyMember;
|
||||
}
|
||||
else if (settings.AutoproxyMode == AutoproxyMode.Member)
|
||||
throw APIErrors.MissingAutoproxyMember;
|
||||
|
||||
var newSettings = await _repo.UpdateSystemGuild(system.Id, guild_id, patch);
|
||||
|
||||
PKMember? newMember = null;
|
||||
if (newSettings.AutoproxyMember != null)
|
||||
newMember = await _repo.GetMember(newSettings.AutoproxyMember.Value);
|
||||
return Ok(newSettings.ToJson(newMember?.Hid));
|
||||
}
|
||||
|
||||
[HttpGet("members/{member}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> MemberGuildGet(string member, ulong guild_id)
|
||||
[HttpGet("members/{memberRef}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> MemberGuildGet(string memberRef, ulong guild_id)
|
||||
{
|
||||
return new ObjectResult("Unimplemented")
|
||||
{
|
||||
StatusCode = 501
|
||||
};
|
||||
var system = await ResolveSystem("@me");
|
||||
var member = await ResolveMember(memberRef);
|
||||
if (member == null)
|
||||
throw APIErrors.MemberNotFound;
|
||||
if (member.System != system.Id)
|
||||
throw APIErrors.NotOwnMemberError;
|
||||
|
||||
var settings = await _repo.GetMemberGuild(guild_id, member.Id, defaultInsert: false);
|
||||
if (settings == null)
|
||||
throw APIErrors.MemberGuildNotFound;
|
||||
|
||||
return Ok(settings.ToJson());
|
||||
}
|
||||
|
||||
[HttpPatch("members/{member}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> MemberGuildPatch(string member, ulong guild_id, [FromBody] JObject data)
|
||||
[HttpPatch("members/{memberRef}/guilds/{guild_id}")]
|
||||
public async Task<IActionResult> DoMemberGuildPatch(string memberRef, ulong guild_id, [FromBody] JObject data)
|
||||
{
|
||||
return new ObjectResult("Unimplemented")
|
||||
var system = await ResolveSystem("@me");
|
||||
var member = await ResolveMember(memberRef);
|
||||
if (member == null)
|
||||
throw APIErrors.MemberNotFound;
|
||||
if (member.System != system.Id)
|
||||
throw APIErrors.NotOwnMemberError;
|
||||
|
||||
var settings = await _repo.GetMemberGuild(guild_id, member.Id, defaultInsert: false);
|
||||
if (settings == null)
|
||||
throw APIErrors.MemberGuildNotFound;
|
||||
|
||||
MemberGuildPatch patch = null;
|
||||
try
|
||||
{
|
||||
StatusCode = 501
|
||||
};
|
||||
patch = MemberGuildPatch.FromJson(data);
|
||||
patch.AssertIsValid();
|
||||
}
|
||||
catch (ValidationError e)
|
||||
{
|
||||
// todo
|
||||
return BadRequest(e.Message);
|
||||
}
|
||||
|
||||
var newSettings = await _repo.UpdateMemberGuild(member.Id, guild_id, patch);
|
||||
return Ok(newSettings.ToJson());
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace PluralKit.API
|
||||
|
||||
public class ModelParseError: PKError
|
||||
{
|
||||
public ModelParseError() : base(400, 0, "Error parsing JSON model")
|
||||
public ModelParseError() : base(400, 40001, "Error parsing JSON model")
|
||||
{
|
||||
// todo
|
||||
}
|
||||
@ -47,16 +47,19 @@ namespace PluralKit.API
|
||||
public static PKError GroupNotFound = new(404, 20003, "Group not found.");
|
||||
public static PKError MessageNotFound = new(404, 20004, "Message not found.");
|
||||
public static PKError SwitchNotFound = new(404, 20005, "Switch not found, switch is associated to different system, or unauthorized to view front history.");
|
||||
public static PKError SystemGuildNotFound = new(404, 20006, "No system guild settings found for target guild.");
|
||||
public static PKError MemberGuildNotFound = new(404, 20007, "No member guild settings found for target guild.");
|
||||
public static PKError UnauthorizedMemberList = new(403, 30001, "Unauthorized to view member list");
|
||||
public static PKError UnauthorizedGroupList = new(403, 30002, "Unauthorized to view group list");
|
||||
public static PKError UnauthorizedGroupMemberList = new(403, 30003, "Unauthorized to view group member list");
|
||||
public static PKError UnauthorizedCurrentFronters = new(403, 30004, "Unauthorized to view current fronters.");
|
||||
public static PKError UnauthorizedFrontHistory = new(403, 30005, "Unauthorized to view front history.");
|
||||
public static PKError NotOwnMemberError = new(403, 40001, "Target member is not part of your system.");
|
||||
public static PKError NotOwnGroupError = new(403, 40002, "Target group is not part of your system.");
|
||||
public static PKError NotOwnMemberError = new(403, 30006, "Target member is not part of your system.");
|
||||
public static PKError NotOwnGroupError = new(403, 30006, "Target group is not part of your system.");
|
||||
// todo: somehow add the memberRef to the JSON
|
||||
public static PKError NotOwnMemberErrorWithRef(string memberRef) => new(403, 40003, $"Member '{memberRef}' is not part of your system.");
|
||||
public static PKError NotOwnGroupErrorWithRef(string groupRef) => new(403, 40004, $"Group '{groupRef}' is not part of your system.");
|
||||
public static PKError NotOwnMemberErrorWithRef(string memberRef) => new(403, 30008, $"Member '{memberRef}' is not part of your system.");
|
||||
public static PKError NotOwnGroupErrorWithRef(string groupRef) => new(403, 30009, $"Group '{groupRef}' is not part of your system.");
|
||||
public static PKError MissingAutoproxyMember = new(400, 40002, "Missing autoproxy member for member-mode autoproxy.");
|
||||
public static PKError Unimplemented = new(501, 50001, "Unimplemented");
|
||||
}
|
||||
}
|
@ -21,8 +21,14 @@ namespace PluralKit.Core
|
||||
}
|
||||
|
||||
|
||||
public Task<SystemGuildSettings> GetSystemGuild(ulong guild, SystemId system)
|
||||
public Task<SystemGuildSettings> GetSystemGuild(ulong guild, SystemId system, bool defaultInsert = true)
|
||||
{
|
||||
if (!defaultInsert)
|
||||
return _db.QueryFirst<SystemGuildSettings>(new Query("system_guild")
|
||||
.Where("guild", guild)
|
||||
.Where("system", system)
|
||||
);
|
||||
|
||||
var query = new Query("system_guild").AsInsert(new
|
||||
{
|
||||
guild = guild,
|
||||
@ -33,16 +39,22 @@ namespace PluralKit.Core
|
||||
);
|
||||
}
|
||||
|
||||
public Task UpdateSystemGuild(SystemId system, ulong guild, SystemGuildPatch patch)
|
||||
public Task<SystemGuildSettings> UpdateSystemGuild(SystemId system, ulong guild, SystemGuildPatch patch)
|
||||
{
|
||||
_logger.Information("Updated {SystemId} in guild {GuildId}: {@SystemGuildPatch}", system, guild, patch);
|
||||
var query = patch.Apply(new Query("system_guild").Where("system", system).Where("guild", guild));
|
||||
return _db.ExecuteQuery(query, extraSql: "returning *");
|
||||
return _db.QueryFirst<SystemGuildSettings>(query, extraSql: "returning *");
|
||||
}
|
||||
|
||||
|
||||
public Task<MemberGuildSettings> GetMemberGuild(ulong guild, MemberId member)
|
||||
public Task<MemberGuildSettings> GetMemberGuild(ulong guild, MemberId member, bool defaultInsert = true)
|
||||
{
|
||||
if (!defaultInsert)
|
||||
return _db.QueryFirst<MemberGuildSettings>(new Query("member_guild")
|
||||
.Where("guild", guild)
|
||||
.Where("member", member)
|
||||
);
|
||||
|
||||
var query = new Query("member_guild").AsInsert(new
|
||||
{
|
||||
guild = guild,
|
||||
@ -53,11 +65,11 @@ namespace PluralKit.Core
|
||||
);
|
||||
}
|
||||
|
||||
public Task UpdateMemberGuild(MemberId member, ulong guild, MemberGuildPatch patch)
|
||||
public Task<MemberGuildSettings> UpdateMemberGuild(MemberId member, ulong guild, MemberGuildPatch patch)
|
||||
{
|
||||
_logger.Information("Updated {MemberId} in guild {GuildId}: {@MemberGuildPatch}", member, guild, patch);
|
||||
var query = patch.Apply(new Query("member_guild").Where("member", member).Where("guild", guild));
|
||||
return _db.ExecuteQuery(query, extraSql: "returning *");
|
||||
return _db.QueryFirst<MemberGuildSettings>(query, extraSql: "returning *");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
#nullable enable
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
@ -8,4 +10,17 @@ namespace PluralKit.Core
|
||||
public string? DisplayName { get; }
|
||||
public string? AvatarUrl { get; }
|
||||
}
|
||||
|
||||
public static class MemberGuildExt
|
||||
{
|
||||
public static JObject ToJson(this MemberGuildSettings settings)
|
||||
{
|
||||
var o = new JObject();
|
||||
|
||||
o.Add("display_name", settings.DisplayName);
|
||||
o.Add("avatar_url", settings.AvatarUrl);
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#nullable enable
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using SqlKata;
|
||||
|
||||
namespace PluralKit.Core
|
||||
@ -13,5 +15,28 @@ namespace PluralKit.Core
|
||||
.With("display_name", DisplayName)
|
||||
.With("avatar_url", AvatarUrl)
|
||||
);
|
||||
|
||||
public new void AssertIsValid()
|
||||
{
|
||||
if (DisplayName.Value != null)
|
||||
AssertValid(DisplayName.Value, "display_name", Limits.MaxMemberNameLength);
|
||||
if (AvatarUrl.Value != null)
|
||||
AssertValid(AvatarUrl.Value, "avatar_url", Limits.MaxUriLength,
|
||||
s => MiscUtils.TryMatchUri(s, out var avatarUri));
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
public static MemberGuildPatch FromJson(JObject o)
|
||||
{
|
||||
var patch = new MemberGuildPatch();
|
||||
|
||||
if (o.ContainsKey("display_name"))
|
||||
patch.DisplayName = o.Value<string>("display_name").NullIfEmpty();
|
||||
|
||||
if (o.ContainsKey("avatar_url"))
|
||||
patch.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty();
|
||||
|
||||
return patch;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#nullable enable
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using SqlKata;
|
||||
|
||||
namespace PluralKit.Core
|
||||
@ -19,5 +21,33 @@ namespace PluralKit.Core
|
||||
.With("tag", Tag)
|
||||
.With("tag_enabled", TagEnabled)
|
||||
);
|
||||
|
||||
public new void AssertIsValid()
|
||||
{
|
||||
if (Tag.Value != null)
|
||||
AssertValid(Tag.Value, "tag", Limits.MaxSystemTagLength);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
public static SystemGuildPatch FromJson(JObject o, MemberId? memberId)
|
||||
{
|
||||
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") && o["autoproxy_mode"].ParseAutoproxyMode() is { } autoproxyMode)
|
||||
patch.AutoproxyMode = autoproxyMode;
|
||||
|
||||
patch.AutoproxyMember = memberId;
|
||||
|
||||
if (o.ContainsKey("tag"))
|
||||
patch.Tag = o.Value<string>("tag").NullIfEmpty();
|
||||
|
||||
if (o.ContainsKey("tag_enabled") && o["tag_enabled"].Type != JTokenType.Null)
|
||||
patch.TagEnabled = o.Value<bool>("tag_enabled");
|
||||
|
||||
return patch;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace PluralKit.Core
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum AutoproxyMode
|
||||
{
|
||||
Off = 1,
|
||||
@ -20,4 +25,44 @@ namespace PluralKit.Core
|
||||
public string? Tag { get; }
|
||||
public bool TagEnabled { get; }
|
||||
}
|
||||
|
||||
public static class SystemGuildExt
|
||||
{
|
||||
public static JObject ToJson(this SystemGuildSettings settings, string? memberHid = null)
|
||||
{
|
||||
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? ParseAutoproxyMode(this JToken o)
|
||||
{
|
||||
if (o.Type == JTokenType.Null)
|
||||
return AutoproxyMode.Off;
|
||||
else if (o.Type != JTokenType.String)
|
||||
return null;
|
||||
|
||||
var value = o.Value<string>();
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case "off":
|
||||
return AutoproxyMode.Off;
|
||||
case "front":
|
||||
return AutoproxyMode.Front;
|
||||
case "latch":
|
||||
return AutoproxyMode.Latch;
|
||||
case "member":
|
||||
return AutoproxyMode.Member;
|
||||
default:
|
||||
throw new ValidationError($"Value '{value}' is not a valid autoproxy mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user