summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/gl_objects/users.rst27
-rw-r--r--gitlab/tests/test_gitlab.py32
-rw-r--r--gitlab/v4/objects.py12
-rwxr-xr-xtools/cli_test_v4.sh4
-rw-r--r--tools/python_test_v4.py29
5 files changed, 104 insertions, 0 deletions
diff --git a/docs/gl_objects/users.rst b/docs/gl_objects/users.rst
index 3e71ac4..3aa783e 100644
--- a/docs/gl_objects/users.rst
+++ b/docs/gl_objects/users.rst
@@ -153,6 +153,33 @@ Revoke (delete) an impersonation token for a user::
i_t.delete()
+
+User memberships
+=========================
+
+References
+----------
+
+* v4 API:
+
+ + :class:`gitlab.v4.objects.UserMembership`
+ + :class:`gitlab.v4.objects.UserMembershipManager`
+ + :attr:`gitlab.v4.objects.User.memberships`
+
+* GitLab API: https://docs.gitlab.com/ee/api/users.html#user-memberships-admin-only
+
+List direct memberships for a user::
+
+ memberships = user.memberships.list()
+
+List only direct project memberships::
+
+ memberships = user.memberships.list(type='Project')
+
+List only direct group memberships::
+
+ memberships = user.memberships.list('Namespace')
+
Current User
============
diff --git a/gitlab/tests/test_gitlab.py b/gitlab/tests/test_gitlab.py
index b56889a..678c9a2 100644
--- a/gitlab/tests/test_gitlab.py
+++ b/gitlab/tests/test_gitlab.py
@@ -658,6 +658,38 @@ class TestGitlab(unittest.TestCase):
self.assertEqual(user.name, "name")
self.assertEqual(user.id, 1)
+ def test_user_memberships(self):
+ @urlmatch(
+ scheme="http",
+ netloc="localhost",
+ path="/api/v4/users/1/memberships",
+ method="get",
+ )
+ def resp_get_user_memberships(url, request):
+ headers = {"content-type": "application/json"}
+ content = """[
+ {
+ "source_id": 1,
+ "source_name": "Project one",
+ "source_type": "Project",
+ "access_level": "20"
+ },
+ {
+ "source_id": 3,
+ "source_name": "Group three",
+ "source_type": "Namespace",
+ "access_level": "20"
+ }
+ ]"""
+ content = content.encode("utf-8")
+ return response(200, content, headers, None, 5, request)
+
+ with HTTMock(resp_get_user_memberships):
+ user = self.gl.users.get(1, lazy=True)
+ memberships = user.memberships.list()
+ self.assertIsInstance(memberships[0], UserMembership)
+ self.assertEqual(memberships[0].source_type, "Project")
+
def test_user_status(self):
@urlmatch(
scheme="http",
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index 83f77d3..92650b1 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -229,6 +229,17 @@ class UserImpersonationTokenManager(NoUpdateMixin, RESTManager):
_list_filters = ("state",)
+class UserMembership(RESTObject):
+ _id_attr = "source_id"
+
+
+class UserMembershipManager(RetrieveMixin, RESTManager):
+ _path = "/users/%(user_id)s/memberships"
+ _obj_cls = UserMembership
+ _from_parent_attrs = {"user_id": "id"}
+ _list_filters = ("type",)
+
+
class UserProject(RESTObject):
pass
@@ -311,6 +322,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
("gpgkeys", "UserGPGKeyManager"),
("impersonationtokens", "UserImpersonationTokenManager"),
("keys", "UserKeyManager"),
+ ("memberships", "UserMembershipManager"),
("projects", "UserProjectManager"),
("status", "UserStatusManager"),
)
diff --git a/tools/cli_test_v4.sh b/tools/cli_test_v4.sh
index b7ed708..cf157f4 100755
--- a/tools/cli_test_v4.sh
+++ b/tools/cli_test_v4.sh
@@ -61,6 +61,10 @@ testcase "adding member to a project" '
--user-id "$USER_ID" --access-level 40 >/dev/null 2>&1
'
+testcase "listing user memberships" '
+ GITLAB user-membership list --user-id "$USER_ID" >/dev/null 2>&1
+'
+
testcase "file creation" '
GITLAB project-file create --project-id "$PROJECT_ID" \
--file-path README --branch master --content "CONTENT" \
diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py
index 49f99e5..0703ee3 100644
--- a/tools/python_test_v4.py
+++ b/tools/python_test_v4.py
@@ -266,6 +266,35 @@ group1.members.create({"access_level": gitlab.const.GUEST_ACCESS, "user_id": use
group2.members.create({"access_level": gitlab.const.OWNER_ACCESS, "user_id": user2.id})
+# User memberships (admin only)
+memberships1 = user1.memberships.list()
+assert len(memberships1) == 1
+
+memberships2 = user2.memberships.list()
+assert len(memberships2) == 2
+
+membership = memberships1[0]
+assert membership.source_type == "Namespace"
+assert membership.access_level == gitlab.const.OWNER_ACCESS
+
+project_memberships = user1.memberships.list(type="Project")
+assert len(project_memberships) == 0
+
+group_memberships = user1.memberships.list(type="Namespace")
+assert len(group_memberships) == 1
+
+try:
+ membership = user1.memberships.list(type="Invalid")
+except gitlab.GitlabListError as e:
+ error_message = e.error_message
+assert error_message == "type does not have a valid value"
+
+try:
+ user1.memberships.list(sudo=user1.name)
+except gitlab.GitlabListError as e:
+ error_message = e.error_message
+assert error_message == "403 Forbidden"
+
# Administrator belongs to the groups
assert len(group1.members.list()) == 3
assert len(group2.members.list()) == 2