summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-09-12 20:58:31 +0200
committerNejc Habjan <hab.nejc@gmail.com>2021-09-13 08:55:22 +0200
commit4e8e4b4101059eee43c4c012b131355428ebc4f7 (patch)
tree17a058762552947a2c79757ed2e31b4a08050386
parentce4bc0daef355e2d877360c6e496c23856138872 (diff)
downloadgitlab-feat/create-delete-token.tar.gz
feat(objects): support Create and Revoke personal access token APIfeat/create-delete-token
-rw-r--r--docs/gl_objects/personal_access_tokens.rst32
-rw-r--r--gitlab/v4/objects/personal_access_tokens.py23
-rw-r--r--gitlab/v4/objects/users.py2
-rw-r--r--tests/unit/objects/test_personal_access_tokens.py90
4 files changed, 119 insertions, 28 deletions
diff --git a/docs/gl_objects/personal_access_tokens.rst b/docs/gl_objects/personal_access_tokens.rst
index 3cbc744..0704c75 100644
--- a/docs/gl_objects/personal_access_tokens.rst
+++ b/docs/gl_objects/personal_access_tokens.rst
@@ -2,8 +2,6 @@
Personal Access Tokens
######################
-Get a list of personal access tokens
-
References
----------
@@ -12,8 +10,14 @@ References
+ :class:`gitlab.v4.objects.PersonalAccessToken`
+ :class:`gitlab.v4.objects.PersonalAcessTokenManager`
+ :attr:`gitlab.Gitlab.personal_access_tokens`
+ + :class:`gitlab.v4.objects.UserPersonalAccessToken`
+ + :class:`gitlab.v4.objects.UserPersonalAcessTokenManager`
+ + :attr:`gitlab.Gitlab.User.personal_access_tokens`
+
+* GitLab API:
-* GitLab API: https://docs.gitlab.com/ee/api/personal_access_tokens.html
+ + https://docs.gitlab.com/ee/api/personal_access_tokens.html
+ + https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token
Examples
--------
@@ -26,3 +30,25 @@ List personal access tokens::
List personal access tokens from other user_id (admin only)::
access_tokens = gl.personal_access_tokens.list(user_id=25)
+
+Revoke a personal access token fetched via list::
+
+ access_token = access_tokens[0]
+ access_token.delete()
+
+Revoke a personal access token by id::
+
+ gl.personal_access_tokens.delete(123)
+
+Create a personal access token for a user (admin only)::
+
+ user = gl.users.get(25, lazy=True)
+ access_token = user.personal_access_tokens.create({"name": "test", "scopes": "api"})
+
+.. note:: As you can see above, you can only create personal access tokens
+ via the Users API, but you cannot revoke these objects directly.
+ This is because the create API uses a different endpoint than the list and revoke APIs.
+ You need to fetch the token via the list API first to revoke it.
+
+ As of 14.2, GitLab does not provide a GET API for single personal access tokens.
+ You must use the list method to retrieve single tokens.
diff --git a/gitlab/v4/objects/personal_access_tokens.py b/gitlab/v4/objects/personal_access_tokens.py
index a326bd6..6cdb305 100644
--- a/gitlab/v4/objects/personal_access_tokens.py
+++ b/gitlab/v4/objects/personal_access_tokens.py
@@ -1,17 +1,32 @@
-from gitlab.base import RESTManager, RESTObject
-from gitlab.mixins import ListMixin
+from gitlab.base import RequiredOptional, RESTManager, RESTObject
+from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin
__all__ = [
"PersonalAccessToken",
"PersonalAccessTokenManager",
+ "UserPersonalAccessToken",
+ "UserPersonalAccessTokenManager",
]
-class PersonalAccessToken(RESTObject):
+class PersonalAccessToken(ObjectDeleteMixin, RESTObject):
pass
-class PersonalAccessTokenManager(ListMixin, RESTManager):
+class PersonalAccessTokenManager(DeleteMixin, ListMixin, RESTManager):
_path = "/personal_access_tokens"
_obj_cls = PersonalAccessToken
_list_filters = ("user_id",)
+
+
+class UserPersonalAccessToken(RESTObject):
+ pass
+
+
+class UserPersonalAccessTokenManager(CreateMixin, RESTManager):
+ _path = "/users/%(user_id)s/personal_access_tokens"
+ _obj_cls = UserPersonalAccessToken
+ _from_parent_attrs = {"user_id": "id"}
+ _create_attrs = RequiredOptional(
+ required=("name", "scopes"), optional=("expires_at",)
+ )
diff --git a/gitlab/v4/objects/users.py b/gitlab/v4/objects/users.py
index c0f8745..63da837 100644
--- a/gitlab/v4/objects/users.py
+++ b/gitlab/v4/objects/users.py
@@ -17,6 +17,7 @@ from gitlab.mixins import (
from .custom_attributes import UserCustomAttributeManager # noqa: F401
from .events import UserEventManager # noqa: F401
+from .personal_access_tokens import UserPersonalAccessTokenManager # noqa: F401
__all__ = [
"CurrentUserEmail",
@@ -122,6 +123,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
impersonationtokens: "UserImpersonationTokenManager"
keys: "UserKeyManager"
memberships: "UserMembershipManager"
+ personal_access_tokens: UserPersonalAccessTokenManager
projects: "UserProjectManager"
status: "UserStatusManager"
diff --git a/tests/unit/objects/test_personal_access_tokens.py b/tests/unit/objects/test_personal_access_tokens.py
index 920cb1d..065b5c8 100644
--- a/tests/unit/objects/test_personal_access_tokens.py
+++ b/tests/unit/objects/test_personal_access_tokens.py
@@ -1,46 +1,94 @@
"""
-GitLab API: https://docs.gitlab.com/ee/api/personal_access_tokens.html
+GitLab API:
+https://docs.gitlab.com/ee/api/personal_access_tokens.html
+https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token
"""
import pytest
import responses
+user_id = 1
+token_id = 1
+token_name = "Test Token"
+
+token_url = "http://localhost/api/v4/personal_access_tokens"
+single_token_url = f"{token_url}/{token_id}"
+user_token_url = f"http://localhost/api/v4/users/{user_id}/personal_access_tokens"
+
+content = {
+ "id": token_id,
+ "name": token_name,
+ "revoked": False,
+ "created_at": "2020-07-23T14:31:47.729Z",
+ "scopes": ["api"],
+ "active": True,
+ "user_id": user_id,
+ "expires_at": None,
+}
+
@pytest.fixture
-def resp_list_personal_access_token():
- content = [
- {
- "id": 4,
- "name": "Test Token",
- "revoked": False,
- "created_at": "2020-07-23T14:31:47.729Z",
- "scopes": ["api"],
- "active": True,
- "user_id": 24,
- "expires_at": None,
- }
- ]
+def resp_create_user_personal_access_token():
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.POST,
+ url=user_token_url,
+ json=content,
+ content_type="application/json",
+ status=200,
+ )
+ yield rsps
+
+@pytest.fixture
+def resp_personal_access_token(no_content):
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
rsps.add(
method=responses.GET,
- url="http://localhost/api/v4/personal_access_tokens",
- json=content,
+ url=token_url,
+ json=[content],
content_type="application/json",
status=200,
)
+ rsps.add(
+ method=responses.DELETE,
+ url=single_token_url,
+ json=no_content,
+ content_type="application/json",
+ status=204,
+ )
yield rsps
-def test_list_personal_access_tokens(gl, resp_list_personal_access_token):
+def test_create_personal_access_token(gl, resp_create_user_personal_access_token):
+ user = gl.users.get(1, lazy=True)
+ access_token = user.personal_access_tokens.create(
+ {"name": token_name, "scopes": "api"}
+ )
+ assert access_token.revoked is False
+ assert access_token.name == token_name
+
+
+def test_list_personal_access_tokens(gl, resp_personal_access_token):
access_tokens = gl.personal_access_tokens.list()
assert len(access_tokens) == 1
assert access_tokens[0].revoked is False
- assert access_tokens[0].name == "Test Token"
+ assert access_tokens[0].name == token_name
-def test_list_personal_access_tokens_filter(gl, resp_list_personal_access_token):
- access_tokens = gl.personal_access_tokens.list(user_id=24)
+def test_list_personal_access_tokens_filter(gl, resp_personal_access_token):
+ access_tokens = gl.personal_access_tokens.list(user_id=user_id)
assert len(access_tokens) == 1
assert access_tokens[0].revoked is False
- assert access_tokens[0].user_id == 24
+ assert access_tokens[0].user_id == user_id
+
+
+def test_revoke_personal_access_token(gl, resp_personal_access_token):
+ access_token = gl.personal_access_tokens.list(user_id=user_id)[0]
+ access_token.delete()
+ assert resp_personal_access_token.assert_call_count(single_token_url, 1)
+
+
+def test_revoke_personal_access_token_by_id(gl, resp_personal_access_token):
+ gl.personal_access_tokens.delete(token_id)
+ assert resp_personal_access_token.assert_call_count(single_token_url, 1)