Skip to content

Commit

Permalink
Merge pull request #19 from Goorsky123/more-methods
Browse files Browse the repository at this point in the history
add functions GraphClient.GetToken, (User/Group).GetMemberGroupsAsStrings and Group.ListTransitiveMembers
  • Loading branch information
TerraTalpi authored Dec 14, 2021
2 parents 1a1560d + 8f88e00 commit 2c55157
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 0 deletions.
28 changes: 28 additions & 0 deletions GraphClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ func (g *GraphClient) refreshToken() error {
return err
}

// GetToken returns a copy the currently token used by this GraphClient instance.
func (g *GraphClient) GetToken() Token {
return g.token
}

// makeGETAPICall performs an API-Call to the msgraph API.
func (g *GraphClient) makeGETAPICall(apiCall string, reqParams getRequestParams, v interface{}) error {
return g.makeAPICall(apiCall, http.MethodGet, reqParams, nil, v)
Expand Down Expand Up @@ -356,6 +361,29 @@ func (g *GraphClient) ListGroups(opts ...ListQueryOption) (Groups, error) {
return marsh.Groups, err
}

// getMemberGroups returns a list of all group IDs the user is a member of.
// You can specify the securityGroupsEnabled parameter to only return security group IDs.
//
// Reference: https://docs.microsoft.com/en-us/graph/api/directoryobject-getmembergroups?view=graph-rest-1.0&tabs=http
func (g *GraphClient) getMemberGroups(identifier string, securityEnabledOnly bool, opts ...GetQueryOption) ([]string, error) {
resource := fmt.Sprintf("/directoryObjects/%v/getMemberGroups", identifier)
var post struct {
SecurityEnabledOnly bool `json:"securityEnabledOnly"`
}
var marsh struct {
Groups []string `json:"value"`
}
post.SecurityEnabledOnly = securityEnabledOnly
bodyBytes, err := json.Marshal(post)
if err != nil {
return marsh.Groups, err
}
body := bytes.NewReader(bodyBytes)

err = g.makePOSTAPICall(resource, compileGetQueryOptions(opts), body, &marsh)
return marsh.Groups, err
}

// GetUser returns the user object associated to the given user identified by either
// the given ID or userPrincipalName
// Supports optional OData query parameters https://docs.microsoft.com/en-us/graph/query-parameters
Expand Down
31 changes: 31 additions & 0 deletions Group.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,37 @@ func (g Group) ListMembers(opts ...ListQueryOption) (Users, error) {
return marsh.Users, g.graphClient.makeGETAPICall(resource, compileListQueryOptions(opts), &marsh)
}

// Get a list of the group's members. A group can have users, devices, organizational contacts, and other groups as members.
// This operation is transitive and returns a flat list of all nested members.
// This method will currently ONLY return User-instances of members
// Supports optional OData query parameters https://docs.microsoft.com/en-us/graph/query-parameters
//
// See https://docs.microsoft.com/en-us/graph/api/group-list-transitivemembers?view=graph-rest-1.0&tabs=http
func (g Group) ListTransitiveMembers(opts ...ListQueryOption) (Users, error) {
if g.graphClient == nil {
return nil, ErrNotGraphClientSourced
}
resource := fmt.Sprintf("/groups/%v/transitiveMembers", g.ID)

var marsh struct {
Users Users `json:"value"`
}
marsh.Users.setGraphClient(g.graphClient)
return marsh.Users, g.graphClient.makeGETAPICall(resource, compileListQueryOptions(opts), &marsh)
}

// GetMemberGroupsAsStrings returns a list of all group IDs the user is a member of.
//
// opts ...GetQueryOption - only msgraph.GetWithContext is supported.
//
// Reference: https://docs.microsoft.com/en-us/graph/api/directoryobject-getmembergroups?view=graph-rest-1.0&tabs=http
func (g Group) GetMemberGroupsAsStrings(opts ...GetQueryOption) ([]string, error) {
if g.graphClient == nil {
return nil, ErrNotGraphClientSourced
}
return g.graphClient.getMemberGroups(g.ID, false, opts...) // securityEnabledOnly is not supported for Groups, see documentation / API-reference
}

// UnmarshalJSON implements the json unmarshal to be used by the json-library
func (g *Group) UnmarshalJSON(data []byte) error {
tmp := struct {
Expand Down
69 changes: 69 additions & 0 deletions Group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,72 @@ func TestGroup_String(t *testing.T) {
})
}
}

func TestGroup_ListTransitiveMembers(t *testing.T) {
testGroup := GetTestGroup(t)

tests := []struct {
name string
g Group
wantErr bool
}{
{
name: "GraphClient created Group",
g: testGroup,
wantErr: false,
}, {
name: "Not GraphClient created Group",
g: Group{DisplayName: "Test not GraphClient sourced"},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.g.ListTransitiveMembers()
if (err != nil) != tt.wantErr {
t.Errorf("Group.ListTransitiveMembers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(got) == 0 {
t.Errorf("Group.ListTransitiveMembers() = %v, len(%d), want at least one member of that group", got, len(got))
}
})
}
}

func TestGroup_GetMemberGroupsAsStrings(t *testing.T) {
testGroup := GetTestGroup(t)

tests := []struct {
name string
g Group
opts []GetQueryOption
wantErr bool
}{
{
name: "Test group func GetMembershipGroupsAsStrings",
g: testGroup,
wantErr: false,
}, {
name: "Test group func GetMembershipGroupsAsStrings - no securityGroupsEnabeledF",
g: testGroup,
wantErr: false,
},
{
name: "Group not initialized by GraphClient",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.g.GetMemberGroupsAsStrings(tt.opts...)
if (err != nil) != tt.wantErr {
t.Errorf("Group.GetMemberGroupsAsStrings() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(got) == 0 {
t.Errorf("Group.GetMemberGroupsAsStrings() = %v, len(%d), want at least one value", got, len(got))
}
})
}
}
13 changes: 13 additions & 0 deletions User.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ func (u User) GetFullName() string {
return fmt.Sprintf("%v %v", u.GivenName, u.Surname)
}

// GetMemberGroupsAsStrings returns a list of all group IDs the user is a member of.
// You can specify the securityGroupsEnabeled parameter to only return security group IDs.
//
// opts ...GetQueryOption - only msgraph.GetWithContext is supported.
//
// Reference: https://docs.microsoft.com/en-us/graph/api/directoryobject-getmembergroups?view=graph-rest-1.0&tabs=http
func (u User) GetMemberGroupsAsStrings(securityGroupsEnabeled bool, opts ...GetQueryOption) ([]string, error) {
if u.graphClient == nil {
return nil, ErrNotGraphClientSourced
}
return u.graphClient.getMemberGroups(u.ID, securityGroupsEnabeled, opts...)
}

// PrettySimpleString returns the User-instance simply formatted for logging purposes: {FullName (email) (activePhone)}
func (u User) PrettySimpleString() string {
return fmt.Sprintf("{ %v (%v) (%v) }", u.GetFullName(), u.Mail, u.GetActivePhone())
Expand Down
43 changes: 43 additions & 0 deletions User_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,49 @@ func TestUser_String(t *testing.T) {
})
}

func TestUser_GetMemberGroupsAsStrings(t *testing.T) {
u := GetTestUser(t)
tests := []struct {
name string
u User
securityGroupsEnabeled bool
opt GetQueryOption
wantErr bool
}{
{
name: "Test user func GetMembershipGroupsAsStrings",
u: u,
securityGroupsEnabeled: true,
opt: GetWithContext(nil),
wantErr: false,
}, {
name: "Test user func GetMembershipGroupsAsStrings - no securityGroupsEnabeledF",
u: u,
securityGroupsEnabeled: false,
opt: GetWithContext(nil),
wantErr: false,
},
{
name: "User not initialized by GraphClient",
securityGroupsEnabeled: true,
opt: GetWithContext(nil),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.u.GetMemberGroupsAsStrings(tt.securityGroupsEnabeled, tt.opt)
if (err != nil) != tt.wantErr {
t.Errorf("User.GetMemberGroupsAsStrings() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(got) == 0 {
t.Errorf("User.GetMemberGroupsAsStrings() = %v, len(%d), want at least one value", got, len(got))
}
})
}
}

func TestUser_UpdateUser(t *testing.T) {
// testing for ErrNotGraphClientSourced
notGraphClientSourcedUser := User{ID: "none"}
Expand Down

0 comments on commit 2c55157

Please sign in to comment.