feat: with_members query string on /systems/:ref/members endpoint
This commit is contained in:
		@@ -18,7 +18,7 @@ namespace PluralKit.API
 | 
				
			|||||||
        public GroupControllerV2(IServiceProvider svc) : base(svc) { }
 | 
					        public GroupControllerV2(IServiceProvider svc) : base(svc) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpGet("systems/{systemRef}/groups")]
 | 
					        [HttpGet("systems/{systemRef}/groups")]
 | 
				
			||||||
        public async Task<IActionResult> GetSystemGroups(string systemRef)
 | 
					        public async Task<IActionResult> GetSystemGroups(string systemRef, [FromQuery] bool with_members)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var system = await ResolveSystem(systemRef);
 | 
					            var system = await ResolveSystem(systemRef);
 | 
				
			||||||
            if (system == null)
 | 
					            if (system == null)
 | 
				
			||||||
@@ -26,14 +26,29 @@ namespace PluralKit.API
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var ctx = this.ContextFor(system);
 | 
					            var ctx = this.ContextFor(system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (with_members && !system.MemberListPrivacy.CanAccess(ctx))
 | 
				
			||||||
 | 
					                throw Errors.UnauthorizedMemberList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!system.GroupListPrivacy.CanAccess(User.ContextFor(system)))
 | 
					            if (!system.GroupListPrivacy.CanAccess(User.ContextFor(system)))
 | 
				
			||||||
                throw Errors.UnauthorizedGroupList;
 | 
					                throw Errors.UnauthorizedGroupList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var groups = _repo.GetSystemGroups(system.Id);
 | 
					            var groups = _repo.GetSystemGroups(system.Id);
 | 
				
			||||||
            return Ok(await groups
 | 
					
 | 
				
			||||||
 | 
					            var j_groups = await groups
 | 
				
			||||||
                .Where(g => g.Visibility.CanAccess(ctx))
 | 
					                .Where(g => g.Visibility.CanAccess(ctx))
 | 
				
			||||||
                .Select(g => g.ToJson(ctx))
 | 
					                .Select(g => g.ToJson(ctx, needsMembersArray: with_members))
 | 
				
			||||||
                .ToListAsync());
 | 
					                .ToListAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (with_members && j_groups.Count > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var q = await _repo.GetGroupMemberInfo(await groups.Select(x => x.Id).ToListAsync());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var row in q)
 | 
				
			||||||
 | 
					                    if (row.MemberVisibility.CanAccess(ctx))
 | 
				
			||||||
 | 
					                        ((JArray)j_groups.Find(x => x.Value<string>("id") == row.Group)["members"]).Add(row.MemberUuid);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Ok(j_groups);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpPost("groups")]
 | 
					        [HttpPost("groups")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,6 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using SqlKata;
 | 
					using SqlKata;
 | 
				
			||||||
@@ -25,6 +27,15 @@ namespace PluralKit.Core
 | 
				
			|||||||
            return _db.QueryStream<PKMember>(query);
 | 
					            return _db.QueryStream<PKMember>(query);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Task<IEnumerable<GroupMember>> GetGroupMemberInfo(IEnumerable<GroupId> ids)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return _db.Query<GroupMember>(new Query("group_members")
 | 
				
			||||||
 | 
					                .LeftJoin("groups", "groups.id", "group_members.group_id")
 | 
				
			||||||
 | 
					                .LeftJoin("members", "members.id", "group_members.member_id")
 | 
				
			||||||
 | 
					                .Select("groups.hid as group", "members.hid as member", "members.uuid as member_uuid", "members.member_visibility")
 | 
				
			||||||
 | 
					                .WhereIn("group_members.group_id", ids.Select(x => x.Value).ToArray()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // todo: add this to metrics tracking
 | 
					        // todo: add this to metrics tracking
 | 
				
			||||||
        public async Task AddGroupsToMember(MemberId member, IReadOnlyCollection<GroupId> groups)
 | 
					        public async Task AddGroupsToMember(MemberId member, IReadOnlyCollection<GroupId> groups)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -93,4 +104,12 @@ namespace PluralKit.Core
 | 
				
			|||||||
            return _db.ExecuteQuery(query);
 | 
					            return _db.ExecuteQuery(query);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class GroupMember
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public string Group { get; set; }
 | 
				
			||||||
 | 
					        public string Member { get; set; }
 | 
				
			||||||
 | 
					        public Guid MemberUuid { get; set; }
 | 
				
			||||||
 | 
					        public PrivacyLevel MemberVisibility { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -61,7 +61,7 @@ namespace PluralKit.Core
 | 
				
			|||||||
        public static string? IconFor(this PKGroup group, LookupContext ctx) =>
 | 
					        public static string? IconFor(this PKGroup group, LookupContext ctx) =>
 | 
				
			||||||
            group.IconPrivacy.Get(ctx, group.Icon?.TryGetCleanCdnUrl());
 | 
					            group.IconPrivacy.Get(ctx, group.Icon?.TryGetCleanCdnUrl());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static JObject ToJson(this PKGroup group, LookupContext ctx, string? systemStr = null, bool isExport = false)
 | 
					        public static JObject ToJson(this PKGroup group, LookupContext ctx, string? systemStr = null, bool needsMembersArray = false)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var o = new JObject();
 | 
					            var o = new JObject();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,7 +80,7 @@ namespace PluralKit.Core
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            o.Add("created", group.Created.FormatExport());
 | 
					            o.Add("created", group.Created.FormatExport());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (isExport)
 | 
					            if (needsMembersArray)
 | 
				
			||||||
                o.Add("members", new JArray());
 | 
					                o.Add("members", new JArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (ctx == LookupContext.ByOwner)
 | 
					            if (ctx == LookupContext.ByOwner)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,15 +40,11 @@ namespace PluralKit.Core
 | 
				
			|||||||
            o.Add("members", new JArray((await _repo.GetSystemMembers(system.Id).ToListAsync()).Select(m => m.ToJson(LookupContext.ByOwner))));
 | 
					            o.Add("members", new JArray((await _repo.GetSystemMembers(system.Id).ToListAsync()).Select(m => m.ToJson(LookupContext.ByOwner))));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var groups = (await _repo.GetSystemGroups(system.Id).ToListAsync());
 | 
					            var groups = (await _repo.GetSystemGroups(system.Id).ToListAsync());
 | 
				
			||||||
            var j_groups = groups.Select(x => x.ToJson(LookupContext.ByOwner, isExport: true)).ToList();
 | 
					            var j_groups = groups.Select(x => x.ToJson(LookupContext.ByOwner, needsMembersArray: true)).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (groups.Count > 0)
 | 
					            if (groups.Count > 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var q = await conn.QueryAsync<GroupMember>(@$"select groups.hid as group, members.hid as member from group_members
 | 
					                var q = await _repo.GetGroupMemberInfo(groups.Select(x => x.Id));
 | 
				
			||||||
                        left join groups on groups.id = group_members.group_id
 | 
					 | 
				
			||||||
                        left join members on members.id = group_members.member_id 
 | 
					 | 
				
			||||||
                    where group_members.group_id in ({string.Join(", ", groups.Select(x => x.Id.Value.ToString()))})
 | 
					 | 
				
			||||||
                ");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                foreach (var row in q)
 | 
					                foreach (var row in q)
 | 
				
			||||||
                    ((JArray)j_groups.Find(x => x.Value<string>("id") == row.Group)["members"]).Add(row.Member);
 | 
					                    ((JArray)j_groups.Find(x => x.Value<string>("id") == row.Group)["members"]).Add(row.Member);
 | 
				
			||||||
@@ -80,10 +76,4 @@ namespace PluralKit.Core
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class GroupMember
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public string Group { get; set; }
 | 
					 | 
				
			||||||
        public string Member { get; set; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -136,6 +136,11 @@ Returns a [member guild settings](/api/models#member-guild-settings) object on s
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
GET `/systems/{systemRef}/groups`
 | 
					GET `/systems/{systemRef}/groups`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Query String Parameters
 | 
				
			||||||
 | 
					|name|type|description
 | 
				
			||||||
 | 
					|---|---|---|
 | 
				
			||||||
 | 
					|with_members|boolean|includes `members` key with array of member UUIDs in each group object|
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Returns a list of [group objects](/api/models/#group-model).
 | 
					Returns a list of [group objects](/api/models/#group-model).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Create Group
 | 
					### Create Group
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user