| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e06c51b commit e456869
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -67,6 +67,11 @@ Activate/Deactivate a user:: | |||
| 67 | 67 | user.activate() | |
| 68 | 68 | user.deactivate() | |
| 69 | 69 | ||
| 70 | + Follow/Unfollow a user:: | ||
| 71 | + | ||
| 72 | + user.follow() | ||
| 73 | + user.unfollow() | ||
| 74 | + | ||
| 70 | 75 | Set the avatar image for a user:: | |
| 71 | 76 | ||
| 72 | 77 | # 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:: | |||
| 84 | 89 | ||
| 85 | 90 | user.identityproviders.delete('oauth2_generic') | |
| 86 | 91 | ||
| 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 | + | ||
| 87 | 101 | User custom attributes | |
| 88 | 102 | ====================== | |
| 89 | 103 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -261,6 +261,14 @@ class GitlabLicenseError(GitlabOperationError): | |||
| 261 | 261 | pass | |
| 262 | 262 | ||
| 263 | 263 | ||
| 264 | + class GitlabFollowError(GitlabOperationError): | ||
| 265 | + pass | ||
| 266 | + | ||
| 267 | + | ||
| 268 | + class GitlabUnfollowError(GitlabOperationError): | ||
| 269 | + pass | ||
| 270 | + | ||
| 271 | + | ||
| 264 | 272 | def on_http_error(error): | |
| 265 | 273 | """Manage GitlabHttpError exceptions. | |
| 266 | 274 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -108,6 +108,72 @@ def resp_delete_user_identity(no_content): | |||
| 108 | 108 | yield rsps | |
| 109 | 109 | ||
| 110 | 110 | ||
| 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 | + | ||
| 111 | 177 | def test_get_user(gl, resp_get_user): | |
| 112 | 178 | user = gl.users.get(1) | |
| 113 | 179 | assert isinstance(user, User) | |
@@ -135,3 +201,17 @@ def test_user_activate_deactivate(user, resp_activate): | |||
| 135 | 201 | ||
| 136 | 202 | def test_delete_user_identity(user, resp_delete_user_identity): | |
| 137 | 203 | 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 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -106,6 +106,8 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject): | |||
| 106 | 106 | _managers = ( | |
| 107 | 107 | ("customattributes", "UserCustomAttributeManager"), | |
| 108 | 108 | ("emails", "UserEmailManager"), | |
| 109 | + ("followers_users", "UserFollowersManager"), | ||
| 110 | + ("following_users", "UserFollowingManager"), | ||
| 109 | 111 | ("events", "UserEventManager"), | |
| 110 | 112 | ("gpgkeys", "UserGPGKeyManager"), | |
| 111 | 113 | ("identityproviders", "UserIdentityProviderManager"), | |
@@ -137,6 +139,42 @@ def block(self, **kwargs): | |||
| 137 | 139 | self._attrs["state"] = "blocked" | |
| 138 | 140 | return server_data | |
| 139 | 141 | ||
| 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 | + | ||
| 140 | 178 | @cli.register_custom_action("User") | |
| 141 | 179 | @exc.on_http_error(exc.GitlabUnblockError) | |
| 142 | 180 | def unblock(self, **kwargs): | |
@@ -454,3 +492,15 @@ def list(self, **kwargs): | |||
| 454 | 492 | else: | |
| 455 | 493 | path = "/users/%s/projects" % kwargs["user_id"] | |
| 456 | 494 | 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"} | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments