Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support API endpoint: List memberships for a billable member of a group #2021

Merged
merged 2 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 70 additions & 30 deletions group_members.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@ type GroupMembersService struct {
client *Client
}

// GroupMemberSAMLIdentity represents the SAML Identity link for the group member.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/members.html#list-all-members-of-a-group-or-project
// Gitlab MR for API change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20357
// Gitlab MR for API Doc change: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25652
type GroupMemberSAMLIdentity struct {
ExternUID string `json:"extern_uid"`
Provider string `json:"provider"`
SAMLProviderID int `json:"saml_provider_id"`
}

// GroupMember represents a GitLab group member.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/members.html
Expand All @@ -59,6 +48,50 @@ type GroupMember struct {
MemberRole *MemberRole `json:"member_role"`
}

// GroupMemberSAMLIdentity represents the SAML Identity link for the group member.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/members.html#list-all-members-of-a-group-or-project
type GroupMemberSAMLIdentity struct {
ExternUID string `json:"extern_uid"`
Provider string `json:"provider"`
SAMLProviderID int `json:"saml_provider_id"`
}

// BillableGroupMember represents a GitLab billable group member.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/members.html#list-all-billable-members-of-a-group
type BillableGroupMember struct {
ID int `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
Email string `json:"email"`
LastActivityOn *ISOTime `json:"last_activity_on"`
MembershipType string `json:"membership_type"`
Removable bool `json:"removable"`
CreatedAt *time.Time `json:"created_at"`
IsLastOwner bool `json:"is_last_owner"`
LastLoginAt *time.Time `json:"last_login_at"`
}

// BillableUserMembership represents a Membership of a billable user of a group
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/members.html#list-memberships-for-a-billable-member-of-a-group
type BillableUserMembership struct {
ID int `json:"id"`
SourceID int `json:"source_id"`
SourceFullName string `json:"source_full_name"`
SourceMembersURL string `json:"source_members_url"`
CreatedAt *time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at"`
AccessLevel *AccessLevelDetails `json:"access_level"`
}

// ListGroupMembersOptions represents the available ListGroupMembers() and
// ListAllGroupMembers() options.
//
Expand Down Expand Up @@ -184,25 +217,6 @@ func (s *GroupMembersService) GetInheritedGroupMember(gid interface{}, user int,
return gm, resp, err
}

// BillableGroupMember represents a GitLab billable group member.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/members.html#list-all-billable-members-of-a-group
type BillableGroupMember struct {
ID int `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
Email string `json:"email"`
LastActivityOn *ISOTime `json:"last_activity_on"`
MembershipType string `json:"membership_type"`
Removable bool `json:"removable"`
CreatedAt *time.Time `json:"created_at"`
IsLastOwner bool `json:"is_last_owner"`
LastLoginAt *time.Time `json:"last_login_at"`
}

// ListBillableGroupMembersOptions represents the available ListBillableGroupMembers() options.
//
// GitLab API docs:
Expand Down Expand Up @@ -239,6 +253,32 @@ func (s *GroupsService) ListBillableGroupMembers(gid interface{}, opt *ListBilla
return bgm, resp, nil
}

// ListMembershipsForBillableGroupMember Gets a list of memberships for a billable member of a group.
// Lists all projects and groups a user is a member of. Only projects and groups within the group hierarchy are included.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/members.html#list-memberships-for-a-billable-member-of-a-group
func (s *GroupsService) ListMembershipsForBillableGroupMember(gid interface{}, user int, options ...RequestOptionFunc) ([]*BillableUserMembership, *Response, error) {
group, err := parseID(gid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("groups/%s/billable_members/%d/memberships", PathEscape(group), user)

req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
if err != nil {
return nil, nil, err
}

var bum []*BillableUserMembership
resp, err := s.client.Do(req, &bum)
if err != nil {
return nil, resp, err
}

return bum, resp, nil
}

// RemoveBillableGroupMember removes a given group members that count as billable.
//
// GitLab API docs:
Expand Down
44 changes: 44 additions & 0 deletions group_members_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,50 @@ func TestListBillableGroupMembers(t *testing.T) {
assert.Equal(t, want, billableMembers, "Expected returned Groups.ListBillableGroupMembers to equal")
}

func TestListMembershipsForBillableGroupMember(t *testing.T) {
mux, client := setup(t)
mux.HandleFunc("/api/v4/groups/1/billable_members/42/memberships",
func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w,
`[
{
"id":21,
"source_id":36,
"source_full_name":"Root Group / Test Group",
"source_members_url":"https://gitlab.example.com/groups/root-group/test-group/-/group_members",
"created_at":"2021-03-31T17:28:44.812Z",
"access_level": {
"string_value": "Developer",
"integer_value": 30
}
}
]`)
})

memberships, _, err := client.Groups.ListMembershipsForBillableGroupMember(1, 42)
if err != nil {
t.Errorf("Groups.ListMembershipsForBillableGroupMember returned error: %v", err)
}

createdAt, _ := time.Parse(time.RFC3339, "2021-03-31T17:28:44.812Z")

want := []*BillableUserMembership{
{
ID: 21,
SourceID: 36,
SourceFullName: "Root Group / Test Group",
SourceMembersURL: "https://gitlab.example.com/groups/root-group/test-group/-/group_members",
CreatedAt: &createdAt,
AccessLevel: &AccessLevelDetails{
IntegerValue: 30,
StringValue: "Developer",
},
},
}
assert.Equal(t, want, memberships, "Expected returned Groups.ListMembershipsForBillableGroupMember to equal")
}

func TestListGroupMembersWithoutEmail(t *testing.T) {
mux, client := setup(t)

Expand Down
5 changes: 5 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ func AccessLevel(v AccessLevelValue) *AccessLevelValue {
return Ptr(v)
}

type AccessLevelDetails struct {
IntegerValue AccessLevelValue `json:"integer_value"`
StringValue string `json:"string_value"`
}

// UserIDValue represents a user ID value within GitLab.
type UserIDValue string

Expand Down