Skip to content

Commit 184b94b

Browse files
Merge pull request #1456 from python-gitlab/feat/billable-members
feat(objects): add support for billable members
2 parents 7824811 + fb0b083 commit 184b94b

File tree

4 files changed

+111
-2
lines changed

4 files changed

+111
-2
lines changed

docs/gl_objects/groups.rst

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,15 @@ Reference
226226
+ :class:`gitlab.v4.objects.GroupMember`
227227
+ :class:`gitlab.v4.objects.GroupMemberManager`
228228
+ :class:`gitlab.v4.objects.GroupMemberAllManager`
229+
+ :class:`gitlab.v4.objects.GroupBillableMember`
230+
+ :class:`gitlab.v4.objects.GroupBillableMemberManager`
229231
+ :attr:`gitlab.v4.objects.Group.members`
230232
+ :attr:`gitlab.v4.objects.Group.members_all`
233+
+ :attr:`gitlab.v4.objects.Group.billable_members`
231234

232-
* GitLab API: https://docs.gitlab.com/ce/api/groups.html
235+
* GitLab API: https://docs.gitlab.com/ce/api/members.html
233236

237+
Billable group members are only available in GitLab EE.
234238

235239
Examples
236240
--------
@@ -270,6 +274,20 @@ Remove a member from the group::
270274
# or
271275
member.delete()
272276

277+
List billable members of a group (top-level groups only)::
278+
279+
billable_members = group.billable_members.list()
280+
281+
Remove a billable member from the group::
282+
283+
group.billable_members.delete(member_id)
284+
# or
285+
billable_member.delete()
286+
287+
List memberships of a billable member::
288+
289+
billable_member.memberships.list()
290+
273291
LDAP group links
274292
================
275293

gitlab/tests/objects/test_members.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
GitLab API: https://docs.gitlab.com/ee/api/members.html
3+
"""
4+
import pytest
5+
import responses
6+
7+
from gitlab.v4.objects import GroupBillableMember
8+
9+
billable_members_content = [
10+
{
11+
"id": 1,
12+
"username": "raymond_smith",
13+
"name": "Raymond Smith",
14+
"state": "active",
15+
"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
16+
"web_url": "http://192.168.1.8:3000/root",
17+
"last_activity_on": "2021-01-27",
18+
"membership_type": "group_member",
19+
"removable": True,
20+
}
21+
]
22+
23+
24+
@pytest.fixture
25+
def resp_list_billable_group_members():
26+
with responses.RequestsMock() as rsps:
27+
rsps.add(
28+
method=responses.GET,
29+
url="http://localhost/api/v4/groups/1/billable_members",
30+
json=billable_members_content,
31+
content_type="application/json",
32+
status=200,
33+
)
34+
yield rsps
35+
36+
37+
@pytest.fixture
38+
def resp_delete_billable_group_member(no_content):
39+
with responses.RequestsMock() as rsps:
40+
rsps.add(
41+
method=responses.DELETE,
42+
url="http://localhost/api/v4/groups/1/billable_members/1",
43+
json=no_content,
44+
content_type="application/json",
45+
status=204,
46+
)
47+
yield rsps
48+
49+
50+
def test_list_group_billable_members(group, resp_list_billable_group_members):
51+
billable_members = group.billable_members.list()
52+
assert isinstance(billable_members, list)
53+
assert isinstance(billable_members[0], GroupBillableMember)
54+
assert billable_members[0].removable is True
55+
56+
57+
def test_delete_group_billable_member(group, resp_delete_billable_group_member):
58+
group.billable_members.delete(1)

gitlab/v4/objects/groups.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
from .export_import import GroupExportManager, GroupImportManager # noqa: F401
1616
from .issues import GroupIssueManager # noqa: F401
1717
from .labels import GroupLabelManager # noqa: F401
18-
from .members import GroupMemberAllManager, GroupMemberManager # noqa: F401
18+
from .members import ( # noqa: F401
19+
GroupBillableMemberManager,
20+
GroupMemberAllManager,
21+
GroupMemberManager,
22+
)
1923
from .merge_requests import GroupMergeRequestManager # noqa: F401
2024
from .milestones import GroupMilestoneManager # noqa: F401
2125
from .notification_settings import GroupNotificationSettingsManager # noqa: F401
@@ -38,6 +42,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
3842
("accessrequests", "GroupAccessRequestManager"),
3943
("audit_events", "GroupAuditEventManager"),
4044
("badges", "GroupBadgeManager"),
45+
("billable_members", "GroupBillableMemberManager"),
4146
("boards", "GroupBoardManager"),
4247
("customattributes", "GroupCustomAttributeManager"),
4348
("exports", "GroupExportManager"),

gitlab/v4/objects/members.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
from gitlab.base import RequiredOptional, RESTManager, RESTObject
33
from gitlab.mixins import (
44
CRUDMixin,
5+
DeleteMixin,
6+
ListMixin,
57
MemberAllMixin,
68
ObjectDeleteMixin,
79
RetrieveMixin,
810
SaveMixin,
911
)
1012

1113
__all__ = [
14+
"GroupBillableMember",
15+
"GroupBillableMemberManager",
16+
"GroupBillableMemberMembership",
17+
"GroupBillableMemberMembershipManager",
1218
"GroupMember",
1319
"GroupMemberManager",
1420
"GroupMemberAllManager",
@@ -35,6 +41,28 @@ class GroupMemberManager(MemberAllMixin, CRUDMixin, RESTManager):
3541
_types = {"user_ids": types.ListAttribute}
3642

3743

44+
class GroupBillableMember(ObjectDeleteMixin, RESTObject):
45+
_short_print_attr = "username"
46+
_managers = (("memberships", "GroupBillableMemberMembershipManager"),)
47+
48+
49+
class GroupBillableMemberManager(ListMixin, DeleteMixin, RESTManager):
50+
_path = "/groups/%(group_id)s/billable_members"
51+
_obj_cls = GroupBillableMember
52+
_from_parent_attrs = {"group_id": "id"}
53+
_list_filters = ("search", "sort")
54+
55+
56+
class GroupBillableMemberMembership(RESTObject):
57+
_id_attr = "user_id"
58+
59+
60+
class GroupBillableMemberMembershipManager(ListMixin, RESTManager):
61+
_path = "/groups/%(group_id)s/billable_members/%(user_id)s/memberships"
62+
_obj_cls = GroupBillableMemberMembership
63+
_from_parent_attrs = {"group_id": "group_id", "user_id": "id"}
64+
65+
3866
class GroupMemberAllManager(RetrieveMixin, RESTManager):
3967
_path = "/groups/%(group_id)s/members/all"
4068
_obj_cls = GroupMember

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy