Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite456869

Browse files
committed
feat(users): add follow/unfollow API
1 parente06c51b commite456869

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

‎docs/gl_objects/users.rst‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ Activate/Deactivate a user::
6767
user.activate()
6868
user.deactivate()
6969

70+
Follow/Unfollow a user::
71+
72+
user.follow()
73+
user.unfollow()
74+
7075
Set the avatar image for a user::
7176

7277
# the avatar image can be passed as data (content of the file) or as a file
@@ -84,6 +89,15 @@ Delete an external identity by provider name::
8489

8590
user.identityproviders.delete('oauth2_generic')
8691

92+
Get the followers of a user
93+
94+
user.followers_users.list()
95+
96+
Get the followings of a user
97+
98+
user.following_users.list()
99+
100+
87101
User custom attributes
88102
======================
89103

‎gitlab/exceptions.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,14 @@ class GitlabLicenseError(GitlabOperationError):
261261
pass
262262

263263

264+
class GitlabFollowError(GitlabOperationError):
265+
pass
266+
267+
268+
class GitlabUnfollowError(GitlabOperationError):
269+
pass
270+
271+
264272
def on_http_error(error):
265273
"""Manage GitlabHttpError exceptions.
266274

‎gitlab/tests/objects/test_users.py‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,72 @@ def resp_delete_user_identity(no_content):
108108
yield rsps
109109

110110

111+
@pytest.fixture
112+
def resp_follow_unfollow():
113+
user = {
114+
"id": 1,
115+
"username": "john_smith",
116+
"name": "John Smith",
117+
"state": "active",
118+
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
119+
"web_url": "http://localhost:3000/john_smith",
120+
}
121+
with responses.RequestsMock() as rsps:
122+
rsps.add(
123+
method=responses.POST,
124+
url="http://localhost/api/v4/users/1/follow",
125+
json=user,
126+
content_type="application/json",
127+
status=201,
128+
)
129+
rsps.add(
130+
method=responses.POST,
131+
url="http://localhost/api/v4/users/1/unfollow",
132+
json=user,
133+
content_type="application/json",
134+
status=201,
135+
)
136+
yield rsps
137+
138+
139+
@pytest.fixture
140+
def resp_followers_following():
141+
content = [
142+
{
143+
"id": 2,
144+
"name": "Lennie Donnelly",
145+
"username": "evette.kilback",
146+
"state": "active",
147+
"avatar_url": "https://www.gravatar.com/avatar/7955171a55ac4997ed81e5976287890a?s=80&d=identicon",
148+
"web_url": "http://127.0.0.1:3000/evette.kilback",
149+
},
150+
{
151+
"id": 4,
152+
"name": "Serena Bradtke",
153+
"username": "cammy",
154+
"state": "active",
155+
"avatar_url": "https://www.gravatar.com/avatar/a2daad869a7b60d3090b7b9bef4baf57?s=80&d=identicon",
156+
"web_url": "http://127.0.0.1:3000/cammy",
157+
},
158+
]
159+
with responses.RequestsMock() as rsps:
160+
rsps.add(
161+
method=responses.GET,
162+
url="http://localhost/api/v4/users/1/followers",
163+
json=content,
164+
content_type="application/json",
165+
status=200,
166+
)
167+
rsps.add(
168+
method=responses.GET,
169+
url="http://localhost/api/v4/users/1/following",
170+
json=content,
171+
content_type="application/json",
172+
status=200,
173+
)
174+
yield rsps
175+
176+
111177
def test_get_user(gl, resp_get_user):
112178
user = gl.users.get(1)
113179
assert isinstance(user, User)
@@ -135,3 +201,17 @@ def test_user_activate_deactivate(user, resp_activate):
135201

136202
def test_delete_user_identity(user, resp_delete_user_identity):
137203
user.identityproviders.delete("test_provider")
204+
205+
206+
def test_user_follow_unfollow(user, resp_follow_unfollow):
207+
user.follow()
208+
user.unfollow()
209+
210+
211+
def test_list_followers(user, resp_followers_following):
212+
followers = user.followers_users.list()
213+
followings = user.following_users.list()
214+
assert isinstance(followers[0], User)
215+
assert followers[0].id == 2
216+
assert isinstance(followings[0], User)
217+
assert followings[1].id == 4

‎gitlab/v4/objects/users.py‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
106106
_managers = (
107107
("customattributes", "UserCustomAttributeManager"),
108108
("emails", "UserEmailManager"),
109+
("followers_users", "UserFollowersManager"),
110+
("following_users", "UserFollowingManager"),
109111
("events", "UserEventManager"),
110112
("gpgkeys", "UserGPGKeyManager"),
111113
("identityproviders", "UserIdentityProviderManager"),
@@ -137,6 +139,42 @@ def block(self, **kwargs):
137139
self._attrs["state"] = "blocked"
138140
return server_data
139141

142+
@cli.register_custom_action("User")
143+
@exc.on_http_error(exc.GitlabFollowError)
144+
def follow(self, **kwargs):
145+
"""Follow the user.
146+
147+
Args:
148+
**kwargs: Extra options to send to the server (e.g. sudo)
149+
150+
Raises:
151+
GitlabAuthenticationError: If authentication is not correct
152+
GitlabFollowError: If the user could not be followed
153+
154+
Returns:
155+
dict: The new object data (*not* a RESTObject)
156+
"""
157+
path = "/users/%s/follow" % self.id
158+
return self.manager.gitlab.http_post(path, **kwargs)
159+
160+
@cli.register_custom_action("User")
161+
@exc.on_http_error(exc.GitlabUnfollowError)
162+
def unfollow(self, **kwargs):
163+
"""Unfollow the user.
164+
165+
Args:
166+
**kwargs: Extra options to send to the server (e.g. sudo)
167+
168+
Raises:
169+
GitlabAuthenticationError: If authentication is not correct
170+
GitlabUnfollowError: If the user could not be followed
171+
172+
Returns:
173+
dict: The new object data (*not* a RESTObject)
174+
"""
175+
path = "/users/%s/unfollow" % self.id
176+
return self.manager.gitlab.http_post(path, **kwargs)
177+
140178
@cli.register_custom_action("User")
141179
@exc.on_http_error(exc.GitlabUnblockError)
142180
def unblock(self, **kwargs):
@@ -454,3 +492,15 @@ def list(self, **kwargs):
454492
else:
455493
path = "/users/%s/projects" % kwargs["user_id"]
456494
return ListMixin.list(self, path=path, **kwargs)
495+
496+
497+
class UserFollowersManager(ListMixin, RESTManager):
498+
_path = "/users/%(user_id)s/followers"
499+
_obj_cls = User
500+
_from_parent_attrs = {"user_id": "id"}
501+
502+
503+
class UserFollowingManager(ListMixin, RESTManager):
504+
_path = "/users/%(user_id)s/following"
505+
_obj_cls = User
506+
_from_parent_attrs = {"user_id": "id"}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp