Skip to content

Commit 26a62e1

Browse files
committed
feat(users): Add approve and reject methods to User
As requested in #1604.
1 parent ae7d3b0 commit 26a62e1

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

docs/gl_objects/users.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ List a user's starred projects
106106

107107
user.starred_projects.list()
108108

109+
If the GitLab instance has new user account approval enabled some users may
110+
have ``user.state == 'blocked_pending_approval'``. Administrators can approve
111+
and reject such users::
112+
113+
user.approve()
114+
109115
User custom attributes
110116
======================
111117

gitlab/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,14 @@ class GitlabUnfollowError(GitlabOperationError):
286286
pass
287287

288288

289+
class GitlabUserApproveError(GitlabOperationError):
290+
pass
291+
292+
293+
class GitlabUserRejectError(GitlabOperationError):
294+
pass
295+
296+
289297
# For an explanation of how these type-hints work see:
290298
# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
291299
#

gitlab/v4/objects/users.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,42 @@ def activate(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
283283
self._attrs["state"] = "active"
284284
return server_data
285285

286+
@cli.register_custom_action("User")
287+
@exc.on_http_error(exc.GitlabUserApproveError)
288+
def approve(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
289+
"""Approve a user creation request.
290+
291+
Args:
292+
**kwargs: Extra options to send to the server (e.g. sudo)
293+
294+
Raises:
295+
GitlabAuthenticationError: If authentication is not correct
296+
GitlabUserApproveError: If the user could not be activated
297+
298+
Returns:
299+
The new object data (*not* a RESTObject)
300+
"""
301+
path = f"/users/{self.encoded_id}/approve"
302+
return self.manager.gitlab.http_post(path, **kwargs)
303+
304+
@cli.register_custom_action("User")
305+
@exc.on_http_error(exc.GitlabUserRejectError)
306+
def reject(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
307+
"""Reject a user creation request.
308+
309+
Args:
310+
**kwargs: Extra options to send to the server (e.g. sudo)
311+
312+
Raises:
313+
GitlabAuthenticationError: If authentication is not correct
314+
GitlabUserReject: If the user could not be rejected
315+
316+
Returns:
317+
The new object data (*not* a RESTObject)
318+
"""
319+
path = f"/users/{self.encoded_id}/reject"
320+
return self.manager.gitlab.http_post(path, **kwargs)
321+
286322

287323
class UserManager(CRUDMixin, RESTManager):
288324
_path = "/users"

tests/unit/objects/test_users.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,29 @@ def resp_activate():
8080
yield rsps
8181

8282

83+
@pytest.fixture
84+
def resp_approve():
85+
content = {
86+
"message": "Success",
87+
}
88+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
89+
rsps.add(
90+
method=responses.POST,
91+
url="http://localhost/api/v4/users/1/approve",
92+
json={},
93+
content_type="application/json",
94+
status=201,
95+
)
96+
rsps.add(
97+
method=responses.POST,
98+
url="http://localhost/api/v4/users/1/reject",
99+
json={},
100+
content_type="application/json",
101+
status=201,
102+
)
103+
yield rsps
104+
105+
83106
@pytest.fixture
84107
def resp_get_user_status():
85108
content = {
@@ -216,6 +239,11 @@ def test_user_activate_deactivate(user, resp_activate):
216239
user.deactivate()
217240

218241

242+
def test_user_approve_reject(user, resp_approve):
243+
user.approve()
244+
user.reject()
245+
246+
219247
def test_delete_user_identity(user, resp_delete_user_identity):
220248
user.identityproviders.delete("test_provider")
221249

0 commit comments

Comments
 (0)