From 55de241ad3deb23fde2b66d79485543316775dc3 Mon Sep 17 00:00:00 2001 From: Anton Andersson Date: Tue, 24 Sep 2024 10:36:34 +0200 Subject: [PATCH] Groups: Add GetTransitiveMembers This PR extends the project to include transitive listing of group members as `msgraph.User`. The addition of this method should not be confused with `ListTransitiveMembers` as it returns a `*[]string`, which forces the user to first list, and then get each individual member by ID. More information about the `transitiveMembers` endpoint can be found [here](https://learn.microsoft.com/en-us/graph/api/group-list-transitivemembers?view=graph-rest-1.0&tabs=http) --- msgraph/groups.go | 35 +++++++++++++++++++++++++++++++++++ msgraph/groups_test.go | 23 +++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/msgraph/groups.go b/msgraph/groups.go index 25d58e7b..f25d2ed1 100644 --- a/msgraph/groups.go +++ b/msgraph/groups.go @@ -358,6 +358,41 @@ func (c *GroupsClient) ListMembers(ctx context.Context, id string) (*[]string, i return &ret, status, nil } +// GetTransitiveMembers retrieves all nested members of the specified Group. +// id is the object ID of the group. +func (c *GroupsClient) GetTransitiveMembers(ctx context.Context, groupId string, query odata.Query) (*[]User, int, error) { + query.Expand = odata.Expand{Relationship: "*"} + + resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ + ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + OData: query, + ValidStatusCodes: []int{http.StatusOK}, + Uri: Uri{ + Entity: fmt.Sprintf("/groups/%s/transitiveMembers", groupId), + }, + }) + + if err != nil { + return nil, status, fmt.Errorf("GroupsClient.BaseClient.Get(): %v", err) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, status, fmt.Errorf("io.ReadAll(): %v", err) + } + + var data struct { + Users []User `json:"value"` + } + + if err = json.Unmarshal(respBody, &data); err != nil { + return nil, status, fmt.Errorf("json.Unmarshal(): %v", err) + } + + return &data.Users, status, nil +} + // ListTransitiveMembers retrieves a flat list of all nested members of the specified Group. // id is the object ID of the group. func (c *GroupsClient) ListTransitiveMembers(ctx context.Context, id string) (*[]string, int, error) { diff --git a/msgraph/groups_test.go b/msgraph/groups_test.go index 216ed21f..1d3b5572 100644 --- a/msgraph/groups_test.go +++ b/msgraph/groups_test.go @@ -39,9 +39,11 @@ func TestGroupsClient(t *testing.T) { testGroupsClient_GetOwner(t, c, *group.ID(), (*owners)[0]) members := testGroupsClient_ListMembers(t, c, *group.ID()) - transitiveMembers := testGroupsClient_ListTransitiveMembers(t, c, *group.ID()) + listedTransitiveMembers := testGroupsClient_ListTransitiveMembers(t, c, *group.ID()) + transitiveMembers := testGroupsClient_GetTransitiveMembers(t, c, *group.ID()) testGroupsClient_GetMember(t, c, *group.ID(), (*members)[0]) - testGroupsClient_GetMember(t, c, *group.ID(), (*transitiveMembers)[0]) + testGroupsClient_GetMember(t, c, *group.ID(), (*listedTransitiveMembers)[0]) + testGroupsClient_GetMember(t, c, *group.ID(), *(*transitiveMembers)[0].ID()) testGroupsClient_GetMembers(t, c, *group.ID(), odata.Query{}) group.DisplayName = utils.StringPtr(fmt.Sprintf("test-updated-group-%s", c.RandomString)) @@ -242,6 +244,23 @@ func testGroupsClient_ListMembers(t *testing.T, c *test.Test, id string) (member return } +func testGroupsClient_GetTransitiveMembers(t *testing.T, c *test.Test, id string) (members *[]msgraph.User) { + members, status, err := c.GroupsClient.GetTransitiveMembers(c.Context, id, odata.Query{}) + if err != nil { + t.Fatalf("GroupsClient.GetTransitiveMembers(): %v", err) + } + if status != 200 { + t.Fatalf("GroupsClient.GetTransitiveMembers(): invalid status: %d", status) + } + if members == nil { + t.Fatal("GroupsClient.GetTransitiveMembers(): members was nil") + } + if len(*members) == 0 { + t.Fatal("GroupsClient.GetTransitiveMembers(): members was empty") + } + return +} + func testGroupsClient_ListTransitiveMembers(t *testing.T, c *test.Test, id string) (members *[]string) { members, status, err := c.GroupsClient.ListTransitiveMembers(c.Context, id) if err != nil {