Skip to content

feat(objects): add support for billable members #1456

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

Merged
merged 1 commit into from
May 25, 2021
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
20 changes: 19 additions & 1 deletion docs/gl_objects/groups.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------
Expand Down Expand Up @@ -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
================

Expand Down
58 changes: 58 additions & 0 deletions gitlab/tests/objects/test_members.py
Original file line number Diff line number Diff line change
@@ -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)
7 changes: 6 additions & 1 deletion gitlab/v4/objects/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"),
Expand Down
28 changes: 28 additions & 0 deletions gitlab/v4/objects/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
from gitlab.base import RequiredOptional, RESTManager, RESTObject
from gitlab.mixins import (
CRUDMixin,
DeleteMixin,
ListMixin,
MemberAllMixin,
ObjectDeleteMixin,
RetrieveMixin,
SaveMixin,
)

__all__ = [
"GroupBillableMember",
"GroupBillableMemberManager",
"GroupBillableMemberMembership",
"GroupBillableMemberMembershipManager",
"GroupMember",
"GroupMemberManager",
"GroupMemberAllManager",
Expand All @@ -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
Expand Down