refactor(apiv2): rewrite group member endpoints to be cleaner

This commit is contained in:
spiral 2021-10-30 18:16:18 -04:00
parent 93eef82a83
commit c7126840ed
No known key found for this signature in database
GPG Key ID: A6059F0CA0E1BD31
5 changed files with 208 additions and 159 deletions

View File

@ -42,6 +42,115 @@ namespace PluralKit.API
return Ok(o);
}
[HttpPost("groups/{groupRef}/members/add")]
public async Task<IActionResult> AddGroupMembers(string groupRef, [FromBody] JArray memberRefs)
{
if (memberRefs.Count == 0)
throw Errors.GenericBadRequest;
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var members = new List<MemberId>();
foreach (var JmemberRef in memberRefs)
{
var memberRef = JmemberRef.Value<string>();
var member = await ResolveMember(memberRef);
// todo: have a list of these errors instead of immediately throwing
if (member == null)
throw Errors.MemberNotFoundWithRef(memberRef);
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);
members.Add(member.Id);
}
var existingMembers = await _repo.GetGroupMembers(group.Id).Select(x => x.Id).ToListAsync();
members = members.Where(x => !existingMembers.Contains(x)).ToList();
if (members.Count > 0)
await _repo.AddMembersToGroup(group.Id, members);
return NoContent();
}
[HttpPost("groups/{groupRef}/members/remove")]
public async Task<IActionResult> RemoveGroupMembers(string groupRef, [FromBody] JArray memberRefs)
{
if (memberRefs.Count == 0)
throw Errors.GenericBadRequest;
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var members = new List<MemberId>();
foreach (var JmemberRef in memberRefs)
{
var memberRef = JmemberRef.Value<string>();
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFoundWithRef(memberRef);
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);
members.Add(member.Id);
}
await _repo.RemoveMembersFromGroup(group.Id, members);
return NoContent();
}
[HttpPost("groups/{groupRef}/members/overwrite")]
public async Task<IActionResult> OverwriteGroupMembers(string groupRef, [FromBody] JArray memberRefs)
{
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var members = new List<MemberId>();
foreach (var JmemberRef in memberRefs)
{
var memberRef = JmemberRef.Value<string>();
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFoundWithRef(memberRef);
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);
members.Add(member.Id);
}
await _repo.ClearGroupMembers(group.Id);
if (members.Count > 0)
await _repo.AddMembersToGroup(group.Id, members);
return NoContent();
}
[HttpGet("members/{memberRef}/groups")]
public async Task<IActionResult> GetMemberGroups(string memberRef)
{
@ -62,127 +171,8 @@ namespace PluralKit.API
return Ok(o);
}
[HttpPut("groups/{groupRef}/members/{memberRef}")]
public async Task<IActionResult> GroupMemberPut(string groupRef, string memberRef)
{
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var member = await ResolveMember(memberRef);
Console.WriteLine(member);
if (member == null)
throw Errors.MemberNotFound;
if (member.System != system.Id)
throw Errors.NotOwnMemberError;
var existingMembers = await _repo.GetGroupMembers(group.Id).Select(x => x.Id).ToListAsync();
if (!existingMembers.Contains(member.Id))
await _repo.AddMembersToGroup(group.Id, new List<MemberId>() { member.Id });
return NoContent();
}
[HttpPut("groups/{groupRef}/members")]
public async Task<IActionResult> GroupMembersPut(string groupRef, [FromBody] JArray memberRefs)
{
if (memberRefs.Count == 0)
throw Errors.GenericBadRequest;
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var members = new List<MemberId>();
foreach (var JmemberRef in memberRefs)
{
var memberRef = JmemberRef.Value<string>();
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFound;
if (member.System != system.Id)
throw Errors.NotOwnMemberErrorWithRef(memberRef);
members.Add(member.Id);
}
var existingMembers = await _repo.GetGroupMembers(group.Id).Select(x => x.Id).ToListAsync();
members = members.Where(x => !existingMembers.Contains(x)).ToList();
if (members.Count > 0)
await _repo.AddMembersToGroup(group.Id, members);
return NoContent();
}
[HttpDelete("groups/{groupRef}/members/{memberRef}")]
public async Task<IActionResult> GroupMemberDelete(string groupRef, string memberRef)
{
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFound;
if (member.System != system.Id)
throw Errors.NotOwnMemberError;
await _repo.RemoveMembersFromGroup(group.Id, new List<MemberId>() { member.Id });
return NoContent();
}
[HttpDelete("groups/{groupRef}/members")]
public async Task<IActionResult> GroupMembersDelete(string groupRef, [FromBody] JArray memberRefs)
{
if (memberRefs.Count == 0)
throw Errors.GenericBadRequest;
var system = await ResolveSystem("@me");
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
if (group.System != system.Id)
throw Errors.NotOwnGroupError;
var members = new List<MemberId>();
foreach (var JmemberRef in memberRefs)
{
var memberRef = JmemberRef.Value<string>();
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFound;
if (member.System != system.Id)
throw Errors.NotOwnMemberError;
members.Add(member.Id);
}
await _repo.RemoveMembersFromGroup(group.Id, members);
return NoContent();
}
[HttpPut("members/{memberRef}/groups")]
public async Task<IActionResult> MemberGroupsPut(string memberRef, [FromBody] JArray groupRefs)
[HttpPost("members/{memberRef}/groups/add")]
public async Task<IActionResult> AddMemberGroups(string memberRef, [FromBody] JArray groupRefs)
{
if (groupRefs.Count == 0)
throw Errors.GenericBadRequest;
@ -219,8 +209,8 @@ namespace PluralKit.API
return NoContent();
}
[HttpDelete("members/{memberRef}/groups")]
public async Task<IActionResult> MemberGroupsDelete(string memberRef, [FromBody] JArray groupRefs)
[HttpPost("members/{memberRef}/groups/remove")]
public async Task<IActionResult> RemoveMemberGroups(string memberRef, [FromBody] JArray groupRefs)
{
if (groupRefs.Count == 0)
throw Errors.GenericBadRequest;
@ -241,7 +231,7 @@ namespace PluralKit.API
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFound;
throw Errors.GroupNotFoundWithRef(groupRef);
if (group.System != system.Id)
throw Errors.NotOwnGroupErrorWithRef(groupRef);
@ -253,5 +243,39 @@ namespace PluralKit.API
return NoContent();
}
[HttpPost("members/{memberRef}/groups/overwrite")]
public async Task<IActionResult> OverwriteMemberGroups(string memberRef, [FromBody] JArray groupRefs)
{
var system = await ResolveSystem("@me");
var member = await ResolveMember(memberRef);
if (member == null)
throw Errors.MemberNotFound;
if (member.System != system.Id)
throw Errors.NotOwnMemberError;
var groups = new List<GroupId>();
foreach (var JgroupRef in groupRefs)
{
var groupRef = JgroupRef.Value<string>();
var group = await ResolveGroup(groupRef);
if (group == null)
throw Errors.GroupNotFoundWithRef(groupRef);
if (group.System != system.Id)
throw Errors.NotOwnGroupErrorWithRef(groupRef);
groups.Add(group.Id);
}
await _repo.ClearMemberGroups(member.Id);
if (groups.Count > 0)
await _repo.AddGroupsToMember(member.Id, groups);
return NoContent();
}
}
}

View File

@ -71,12 +71,14 @@ namespace PluralKit.API
public static PKError GenericAuthError = new(401, 0, "401: Missing or invalid Authorization header");
public static PKError SystemNotFound = new(404, 20001, "System not found.");
public static PKError MemberNotFound = new(404, 20002, "Member not found.");
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.");
public static PKError SwitchNotFoundPublic = new(404, 20005, "Switch not found, switch associated with 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 MemberNotFoundWithRef(string memberRef) => new(404, 20003, $"Member '{memberRef}' not found.");
public static PKError GroupNotFound = new(404, 20004, "Group not found.");
public static PKError GroupNotFoundWithRef(string groupRef) => new(404, 20005, $"Group '{groupRef}' not found.");
public static PKError MessageNotFound = new(404, 20006, "Message not found.");
public static PKError SwitchNotFound = new(404, 20007, "Switch not found.");
public static PKError SwitchNotFoundPublic = new(404, 20008, "Switch not found, switch associated with different system, or unauthorized to view front history.");
public static PKError SystemGuildNotFound = new(404, 20009, "No system guild settings found for target guild.");
public static PKError MemberGuildNotFound = new(404, 20010, "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");

View File

@ -76,5 +76,21 @@ namespace PluralKit.Core
.WhereIn("member_id", members);
return _db.ExecuteQuery(query);
}
public Task ClearGroupMembers(GroupId group)
{
_logger.Information("Cleared members of {GroupId}", group);
var query = new Query("group_members").AsDelete()
.Where("group_id", group);
return _db.ExecuteQuery(query);
}
public Task ClearMemberGroups(MemberId member)
{
_logger.Information("Cleared groups of {GroupId}", member);
var query = new Query("group_members").AsDelete()
.Where("member_id", member);
return _db.ExecuteQuery(query);
}
}
}

View File

@ -89,20 +89,26 @@ GET `/members/{memberRef}/groups`
### Add Member To Groups
PUT `/members/{memberRef}/groups`
POST `/members/{memberRef}/groups/add`
::: warning
Not all HTTP implementations support PUT requests with a body. If yours does not, consider using the [Add Member To Group](#add-member-to-group) endpoint instead.
:::
Takes a list of group references as input. Returns 204 No Content on success.
### Remove Member From Groups
DELETE `/members/{memberRef}/groups`
POST `/members/{memberRef}/groups/remove`
::: warning
Not all HTTP implementations support DELETE requests with a body. If yours does not, consider using the [Remove Member From Group](#remove-member-from-group) endpoint instead.
::: tip
If you want to remove *all* groups from a member, consider using the [Overwrite Member Groups](#overwrite-member-groups) endpoint instead.
:::
Takes a list of group references as input. Returns 204 No Content on success.
### Overwrite Member Groups
POST `/members/{memberRef}/groups/overwrite`
Takes a list of group references as input. (An empty list is accepted.) Returns 204 No Content on success.
### Get Member Guild Settings
GET `/members/{memberRef}/guilds/{guild_id}`
@ -164,30 +170,29 @@ Returns 204 No Content on success.
GET `/groups/{groupRef}/members`
### Add Member To Group
PUT `/groups/{groupRef}/members/{memberRef}`
Returns an array of [member objects](/api/models#member-model).
### Add Members To Group
PUT `/groups/{groupRef}/members`
POST `/groups/{groupRef}/members/add`
::: warning
Not all HTTP implementations support PUT requests with a body. If yours does not, consider using the [Add Member To Group](#add-group-member) endpoint instead.
:::
Takes an array of member references as input. Returns 204 No Content on success.
### Remove Member From Group
DELETE `/groups/{groupRef}/members/{memberRef}`
POST `/groups/{groupRef}/members/remove`
### Remove Members From Group
DELETE `/groups/{groupRef}/members`
::: warning
Not all HTTP implementations support DELETE requests with a body. If yours does not, consider using the [Remove Member From Group](#remove-member-from-group) endpoint instead.
::: tip
If you want to remove *all* members from a group, consider using the [Overwrite Group Members](#overwrite-group-members) endpoint instead.
:::
Takes an array of member references as input. Returns 204 No Content on success.
### Overwrite Group Members
POST `/groups/{groupRef}/members/overwrite`
Takes an array of member references as input. (An empty list is accepted.) Returns 204 No Content on success.
---
## Switches

View File

@ -35,12 +35,14 @@ When something goes wrong, the API will send back a 4xx HTTP status code, along
|0|401|Missing or invalid Authorization header|
|20001|404|System not found.|
|20002|404|Member not found.|
|20003|404|Group not found.|
|20004|404|Message not found.|
|20005|404|Switch not found.|
|20005|404|Switch not found, switch associated with different system, or unauthorized to view front history.|
|20006|404|No system guild settings found for target guild.|
|20007|404|No member guild settings found for target guild.|
|20003|404|Member '{memberRef}' not found.|
|20004|404|Group not found.|
|20005|404|Group '{groupRef}' not found.|
|20006|404|Message not found.|
|20007|404|Switch not found.|
|20008|404|Switch not found, switch associated with different system, or unauthorized to view front history.|
|20009|404|No system guild settings found for target guild.|
|20010|404|No member guild settings found for target guild.|
|30001|403|Unauthorized to view member list|
|30002|403|Unauthorized to view group list|
|30003|403|Unauthorized to view group member list|
@ -48,8 +50,8 @@ When something goes wrong, the API will send back a 4xx HTTP status code, along
|30005|403|Unauthorized to view front history.|
|30006|403|Target member is not part of your system.|
|30007|403|Target group is not part of your system.|
|30008|403|$Member '{memberRef}' is not part of your system.|
|30009|403|$Group '{groupRef}' is not part of your system.|
|30008|403|Member '{memberRef}' is not part of your system.|
|30009|403|Group '{groupRef}' is not part of your system.|
|40002|400|Missing autoproxy member for member-mode autoproxy.|
|40003|400|Duplicate members in member list.|
|40004|400|Member list identical to current fronter list.|