From fb0b083a0e536a6abab25c9ad377770cc4290fe9 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Fri, 14 May 2021 23:17:18 +0200 Subject: [PATCH] feat(objects): add support for billable members --- docs/gl_objects/groups.rst | 20 +++++++++- gitlab/tests/objects/test_members.py | 58 ++++++++++++++++++++++++++++ gitlab/v4/objects/groups.py | 7 +++- gitlab/v4/objects/members.py | 28 ++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 gitlab/tests/objects/test_members.py diff --git a/docs/gl_objects/groups.rst b/docs/gl_objects/groups.rst index cd8ab45d0..9f1b049f7 100644 --- a/docs/gl_objects/groups.rst +++ b/docs/gl_objects/groups.rst @@ -226,11 +226,15 @@ Reference + :class:`gitlab.v4.objects.GroupMember` + :class:`gitlab.v4.objects.GroupMemberManager` + :class:`gitlab.v4.objects.GroupMemberAllManager` + + :class:`gitlab.v4.objects.GroupBillableMember` + + :class:`gitlab.v4.objects.GroupBillableMemberManager` + :attr:`gitlab.v4.objects.Group.members` + :attr:`gitlab.v4.objects.Group.members_all` + + :attr:`gitlab.v4.objects.Group.billable_members` -* GitLab API: https://docs.gitlab.com/ce/api/groups.html +* GitLab API: https://docs.gitlab.com/ce/api/members.html +Billable group members are only available in GitLab EE. Examples -------- @@ -270,6 +274,20 @@ Remove a member from the group:: # or member.delete() +List billable members of a group (top-level groups only):: + + billable_members = group.billable_members.list() + +Remove a billable member from the group:: + + group.billable_members.delete(member_id) + # or + billable_member.delete() + +List memberships of a billable member:: + + billable_member.memberships.list() + LDAP group links ================ diff --git a/gitlab/tests/objects/test_members.py b/gitlab/tests/objects/test_members.py new file mode 100644 index 000000000..6a3936911 --- /dev/null +++ b/gitlab/tests/objects/test_members.py @@ -0,0 +1,58 @@ +""" +GitLab API: https://docs.gitlab.com/ee/api/members.html +""" +import pytest +import responses + +from gitlab.v4.objects import GroupBillableMember + +billable_members_content = [ + { + "id": 1, + "username": "raymond_smith", + "name": "Raymond Smith", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + "web_url": "http://192.168.1.8:3000/root", + "last_activity_on": "2021-01-27", + "membership_type": "group_member", + "removable": True, + } +] + + +@pytest.fixture +def resp_list_billable_group_members(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/groups/1/billable_members", + json=billable_members_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture +def resp_delete_billable_group_member(no_content): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.DELETE, + url="http://localhost/api/v4/groups/1/billable_members/1", + json=no_content, + content_type="application/json", + status=204, + ) + yield rsps + + +def test_list_group_billable_members(group, resp_list_billable_group_members): + billable_members = group.billable_members.list() + assert isinstance(billable_members, list) + assert isinstance(billable_members[0], GroupBillableMember) + assert billable_members[0].removable is True + + +def test_delete_group_billable_member(group, resp_delete_billable_group_member): + group.billable_members.delete(1) diff --git a/gitlab/v4/objects/groups.py b/gitlab/v4/objects/groups.py index 8c1b68185..e29edc87a 100644 --- a/gitlab/v4/objects/groups.py +++ b/gitlab/v4/objects/groups.py @@ -15,7 +15,11 @@ from .export_import import GroupExportManager, GroupImportManager # noqa: F401 from .issues import GroupIssueManager # noqa: F401 from .labels import GroupLabelManager # noqa: F401 -from .members import GroupMemberAllManager, GroupMemberManager # noqa: F401 +from .members import ( # noqa: F401 + GroupBillableMemberManager, + GroupMemberAllManager, + GroupMemberManager, +) from .merge_requests import GroupMergeRequestManager # noqa: F401 from .milestones import GroupMilestoneManager # noqa: F401 from .notification_settings import GroupNotificationSettingsManager # noqa: F401 @@ -38,6 +42,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject): ("accessrequests", "GroupAccessRequestManager"), ("audit_events", "GroupAuditEventManager"), ("badges", "GroupBadgeManager"), + ("billable_members", "GroupBillableMemberManager"), ("boards", "GroupBoardManager"), ("customattributes", "GroupCustomAttributeManager"), ("exports", "GroupExportManager"), diff --git a/gitlab/v4/objects/members.py b/gitlab/v4/objects/members.py index a64df24ac..3ff8de54d 100644 --- a/gitlab/v4/objects/members.py +++ b/gitlab/v4/objects/members.py @@ -2,6 +2,8 @@ from gitlab.base import RequiredOptional, RESTManager, RESTObject from gitlab.mixins import ( CRUDMixin, + DeleteMixin, + ListMixin, MemberAllMixin, ObjectDeleteMixin, RetrieveMixin, @@ -9,6 +11,10 @@ ) __all__ = [ + "GroupBillableMember", + "GroupBillableMemberManager", + "GroupBillableMemberMembership", + "GroupBillableMemberMembershipManager", "GroupMember", "GroupMemberManager", "GroupMemberAllManager", @@ -35,6 +41,28 @@ class GroupMemberManager(MemberAllMixin, CRUDMixin, RESTManager): _types = {"user_ids": types.ListAttribute} +class GroupBillableMember(ObjectDeleteMixin, RESTObject): + _short_print_attr = "username" + _managers = (("memberships", "GroupBillableMemberMembershipManager"),) + + +class GroupBillableMemberManager(ListMixin, DeleteMixin, RESTManager): + _path = "/groups/%(group_id)s/billable_members" + _obj_cls = GroupBillableMember + _from_parent_attrs = {"group_id": "id"} + _list_filters = ("search", "sort") + + +class GroupBillableMemberMembership(RESTObject): + _id_attr = "user_id" + + +class GroupBillableMemberMembershipManager(ListMixin, RESTManager): + _path = "/groups/%(group_id)s/billable_members/%(user_id)s/memberships" + _obj_cls = GroupBillableMemberMembership + _from_parent_attrs = {"group_id": "group_id", "user_id": "id"} + + class GroupMemberAllManager(RetrieveMixin, RESTManager): _path = "/groups/%(group_id)s/members/all" _obj_cls = GroupMember