diff --git a/README.md b/README.md index 28028d0..39e868b 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Ordered by https://api.mattermost.com/ + **``patch_user (user_id, props=None, **kwargs)``** + *``update_user_roles() #NOT_IMPLEMENTED``* + *``update_user_active_status() #NOT_IMPLEMENTED``* - + *``get_user_profile_image() #NOT_IMPLEMENTED``* + + **``get_user_profile_image()``** + *``set_user_profile_image() #NOT_IMPLEMENTED``* + *``delete_user_profile_image() #NOT_IMPLEMENTED``* + *``get_user_default_profile_image() #NOT_IMPLEMENTED``* @@ -177,7 +177,7 @@ Ordered by https://api.mattermost.com/ + *``get_team_members_by_id() #NOT_IMPLEMENTED``* + *``get_team_stats() #NOT_IMPLEMENTED``* + *``regenerate_team_invite_id() #NOT_IMPLEMENTED``* - + *``get_team_icon() #NOT_IMPLEMENTED``* + + **``get_team_icon(team_id, **kwargs)** + *``set_team_icon() #NOT_IMPLEMENTED``* + *``remove_team_icon() #NOT_IMPLEMENTED``* + *``update_team_members_roles() #NOT_IMPLEMENTED``* @@ -220,13 +220,16 @@ Ordered by https://api.mattermost.com/ + **``get_post (post_id, **kwargs)``** + **``delete_post (post_id, **kwargs)``** + **``patch_post (post_id, message=None, is_pinned=None, props=None, **kwargs)``** + + **``get_thread(self, post_id, direction='up', **kwargs)``** + **``get_posts_for_channel (channel_id, **kwargs)``** + **FILES** + **``upload_file (channel_id, filepath, **kwargs)``** + **``get_file (file_id, **kwargs)``** + **PREFERENCES** #NOT_IMPLEMENTED + **STATUS** #NOT_IMPLEMENTED -+ **EMOJI** #NOT_IMPLEMENTED ++ **EMOJI** + + **``get_list_of_custom_emojis(self, **kwargs)``** + + **``get_custom_emoji_image(self, emoji_id, **kwargs)``** + **REACTIONS** + **``create_reaction (user_id, post_id, emoji_name, **kwargs)``** + **WEBHOOKS** diff --git a/mattermost/__init__.py b/mattermost/__init__.py index 3bebf8e..ed3ed57 100644 --- a/mattermost/__init__.py +++ b/mattermost/__init__.py @@ -22,7 +22,21 @@ class ApiException(Exception): class MMApi: - """Mattermost API v4 bindings.""" + """Mattermost API v4 bindings. + + A note on methods that return an image: + + These functions return a requests.Response object. Supposed we call it resp, + this is how to handle it. + + If resp.ok is False, there is no image available. Check resp.status_code + and resp.text for details. + + If resp.ok is True, resp.content contains the image's binary image data. + resp.headers['content-type'] contains the MIME type of the image, for + example 'image/png'. + + """ def __init__(self, url): self._url = url @@ -355,7 +369,26 @@ def patch_user(self, user_id, props=None, **kwargs): #def update_user_roles() #NOT_IMPLEMENTED #def update_user_active_status() #NOT_IMPLEMENTED - #def get_user_profile_image() #NOT_IMPLEMENTED + + + + def get_user_profile_image(self, user_id, **kwargs): + """ + Get profile image of a user. + + Args: + user_id (string): User whose image is requested + + Returns: + requests.Response object, see class description how to handle it + + Raises: + ApiException: Passed on from lower layers. + """ + return self._get("/v4/users/"+user_id+"/image", raw=True, **kwargs) + + + #def set_user_profile_image() #NOT_IMPLEMENTED #def delete_user_profile_image() #NOT_IMPLEMENTED #def get_user_default_profile_image() #NOT_IMPLEMENTED @@ -654,7 +687,23 @@ def remove_user_from_team(self, team_id, user_id, **kwargs): #def get_team_members_by_id() #NOT_IMPLEMENTED #def get_team_stats() #NOT_IMPLEMENTED #def regenerate_team_invite_id() #NOT_IMPLEMENTED - #def get_team_icon() #NOT_IMPLEMENTED + + + + def get_team_icon(self, team_id, **kwargs): + """ + Get a team's icon if present + + Args: + team_id (string): team_id to get icon for + + Returns: + requests.Response object, see class description how to handle it + """ + return self._get("/v4/teams/"+team_id+"/image", raw=True, **kwargs) + + + #def set_team_icon() #NOT_IMPLEMENTED #def remove_team_icon() #NOT_IMPLEMENTED #def update_team_members_roles() #NOT_IMPLEMENTED @@ -1219,6 +1268,33 @@ def patch_post(self, post_id, message=None, is_pinned=None, file_ids=None, has_r + def get_thread(self, post_id, direction='up', **kwargs): + """ + Generator: Get all posts in the thread post_id belongs to in the given direction + + Args: + post_id: ID of the post in the thread to start from + direction: either 'up' or 'down' + + Returns: + generates: Posts in the thread + """ + curr_post_id = post_id + while curr_post_id: + data_page = self._get("/v4/posts/"+curr_post_id+"/thread", params={"direction":direction}, **kwargs) + for pid in data_page['order']: + yield data_page['posts'][pid] + + if not data_page['has_next']: + curr_post_id = None + else: + if 'up' == direction: + curr_post_id = data_page['next_post_id'] + else: + curr_post_id = data_page['prev_post_id'] + + + def get_posts_for_channel(self, channel_id, **kwargs): """ Generator: Get a page of posts in a channel. Use the query parameters to modify the behaviour of this endpoint. @@ -1291,7 +1367,50 @@ def get_file(self, file_id, **kwargs): #+ **STATUS** #NOT_IMPLEMENTED ################################################ -#+ **EMOJI** #NOT_IMPLEMENTED +#+ **EMOJI** + + + def get_list_of_custom_emojis(self, **kwargs): + """ + Generator: Get an iterator returning all custom emojis + + Returns: + generates: Emoji + + Raises: + ApiException: Passed on from lower layers. + """ + + page = 0 + while True: + emojis_page = self._get("/v4/emoji", params={"page":str(page)}, **kwargs) + + if not emojis_page: + break + + for emoji in emojis_page: + yield emoji + + page += 1 + + + + def get_custom_emoji_image(self, emoji_id, **kwargs): + """ + Get emoji image. + + Args: + emoji_id (string): Emoji whose image is requested + + Returns: + requests.Response object, see class description how to handle it + + Raises: + ApiException: Passed on from lower layers. + """ + return self._get("/v4/emoji/"+emoji_id+"/image", raw=True, **kwargs) + + ################################################ #+ **REACTIONS**