From 911fcc733cb60694e59f4c2bdf61e66219cd1508 Mon Sep 17 00:00:00 2001 From: Alex McGivern Date: Wed, 26 Apr 2017 12:59:49 +0100 Subject: [PATCH 1/5] added calls for fetching instance data, status cards, filing reports, and updating the user profile --- mastodon/Mastodon.py | 56 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 4717674..919825a 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -213,6 +213,17 @@ class Mastodon: return response['access_token'] + ### + # Reading data: Instance + ### + def instance(self): + """ + Retrieve basic information about the instance, including the URI and administrative contact email. + + Returns a dict. + """ + return self.__api_request('GET', '/api/v1/instance/') + ### # Reading data: Timelines ## @@ -277,6 +288,14 @@ class Mastodon: """ return self.__api_request('GET', '/api/v1/statuses/' + str(id)) + def status_card(self, id): + """ + Fetch a card associated with a status. + + Returns a card dict. + """ + return self.__api_request('GET', '/api/v1/statuses/' + str(id) + '/card') + def status_context(self, id): """ Fetch information about ancestors and descendants of a toot. @@ -392,7 +411,6 @@ class Mastodon: """ params = self.__generate_params(locals()) return self.__api_request('GET', '/api/v1/accounts/search', params) - ### # Reading data: Searching @@ -426,6 +444,17 @@ class Mastodon: """ return self.__api_request('GET', '/api/v1/blocks') + ### + # Reading data: Reports + ### + def reports(self): + """ + Fetch a list of reports made by the authenticated user. + + Returns a list of report dicts. + """ + return self.__api_request('GET', '/api/v1/reports') + ### # Reading data: Favourites ### @@ -611,6 +640,31 @@ class Mastodon: """ return self.__api_request('POST', '/api/v1/accounts/' + str(id) + "/unmute") + def account_update_credentials(self, display_name = None, note = None, avatar = None, header = None): + """ + Update the profile for the currently authenticated user. + + 'note' is the user's bio. + + 'avatar' and 'header' are PNG images encoded in base64. + """ + params = self.__generate_params(locals()) + return self.__api_request('POST', '/api/v1/accounts/update_credentials', params) + + ### + # Writing data: Reports + ### + def report(self, id, toots, comment): + """ + Report a user to the admin. + + Accepts a list of toot IDs associated with the report, and a comment. + + Returns a report dict. + """ + params = self.__generate_params(locals()) + return self.__api_request('POST', '/api/v1/reports/', params) + ### # Writing data: Follow requests ### From 3d5bf0eb0c240bab9789748d33119b8815ef794f Mon Sep 17 00:00:00 2001 From: Alex McGivern Date: Wed, 26 Apr 2017 13:09:58 +0100 Subject: [PATCH 2/5] updated docs with new API calls; updated dict descriptions with missing fields --- docs/index.rst | 101 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 30 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index bad52d2..ee94166 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -88,18 +88,18 @@ User dicts mastodon.account() # Returns the following dictionary: { - 'display_name': # The user's display name - 'acct': # The user's account name as username@domain (@domain omitted for local users) - 'following_count': # How many people they follow - 'url': # Their URL; usually 'https://mastodon.social/users/' - 'statuses_count': # How many statuses they have - 'followers_count': # How many followers they have - 'avatar': # URL for their avatar - 'note': # Their bio - 'header': # URL for their header image 'id': # Same as 'username': # The username (what you @ them with) + 'acct': # The user's account name as username@domain (@domain omitted for local users) + 'display_name': # The user's display name 'locked': # Denotes whether the account can be followed without a follow request + 'following_count': # How many people they follow + 'followers_count': # How many followers they have + 'statuses_count': # How many statuses they have + 'note': # Their bio + 'url': # Their URL; usually 'https://mastodon.social/users/' + 'avatar': # URL for their avatar + 'header': # URL for their header image } Toot dicts @@ -109,24 +109,28 @@ Toot dicts mastodon.toot("Hello from Python") # Returns the following dictionary: { - 'sensitive': # Denotes whether media attachments to the toot are marked sensitive - 'created_at': # Creation time - 'mentions': # A list of account dicts mentioned in the toot + 'id': # Numerical id of this toot 'uri': # Descriptor for the toot # EG 'tag:mastodon.social,2016-11-25:objectId=:objectType=Status' - 'tags': # A list of hashtag dicts used in the toot + 'url': # URL of the toot + 'account': # Account dict for the account which posted the status 'in_reply_to_id': # Numerical id of the toot this toot is in response to - 'media_attachments': # list of media dicts of attached files. Only present - # when there are attached files. - 'id': # Numerical id of this toot + 'in_reply_to_account_id': # Numerical id of the account this toot is in response to + 'reblog': # Denotes whether the toot is a reblog + 'content': # Content of the toot, as HTML: '

Hello from Python

' + 'created_at': # Creation time 'reblogs_count': # Number of reblogs 'favourites_count': # Number of favourites - 'reblog': # Denotes whether the toot is a reblog - 'url': # URL of the toot - 'content': # Content of the toot, as HTML: '

Hello from Python

' - 'spoiler_text': # Warning text that should be displayed before the toot content + 'reblogged': # Denotes whether the logged in user has boosted this toot 'favourited': # Denotes whether the logged in user has favourited this toot - 'account': # Account dict for the logged in account + 'sensitive': # Denotes whether media attachments to the toot are marked sensitive + 'spoiler_text': # Warning text that should be displayed before the toot content + 'visibility': # Toot visibility ('public', 'unlisted', 'private', or 'direct') + 'mentions': # A list of account dicts mentioned in the toot + 'media_attachments': # list of media dicts of attached files. Only present + # when there are attached files. + 'tags': # A list of hashtag dicts used in the toot + 'application': # Application dict for the client used to post the toot } Relationship dicts @@ -136,9 +140,9 @@ Relationship dicts mastodon.account_follow() # Returns the following dictionary: { - 'followed_by': # Boolean denoting whether they follow you back - 'following': # Boolean denoting whether you follow them 'id': # Numerical id (same one as ) + 'following': # Boolean denoting whether you follow them + 'followed_by': # Boolean denoting whether they follow you back 'blocking': # Boolean denoting whether you are blocking them 'muting': # Boolean denoting whether you are muting them 'requested': # Boolean denoting whether you have sent them a follow request @@ -153,9 +157,10 @@ Notification dicts { 'id': # id of the notification. 'type': # "mention", "reblog", "favourite" or "follow". + 'created_at': # The time the notification was created. + 'account': # User dict of the user from whom the notification originates. 'status': # In case of "mention", the mentioning status. # In case of reblog / favourite, the reblogged / favourited status. - 'account': # User dict of the user from whom the notification originates. } Context dicts @@ -165,8 +170,8 @@ Context dicts mastodon.status_context() # Returns the following dictionary: { - 'descendants': # A list of toot dicts 'ancestors': # A list of toot dicts + 'descendants': # A list of toot dicts } Media dicts @@ -176,10 +181,25 @@ Media dicts mastodon.media_post("image.jpg", "image/jpeg") # Returns the following dictionary: { - 'text_url': # The display text for the media (what shows up in toots) - 'preview_url': # The URL for the media preview + 'id': # The ID of the attachment. 'type': # Media type, EG 'image' - 'url': # The URL for the media + 'url': # The URL for the image in the local cache + 'remote_url': # The remote URL for the media (if the image is from a remote instance) + 'preview_url': # The URL for the media preview + 'text_url': # The display text for the media (what shows up in toots) + } + +Card dicts +~~~~~~~~~~ +..code-block:: python + + mastodon.status_card(): + # Returns the folowing dictionary + { + 'url': The URL of the card. + 'title': The title of the card. + 'description': The description of the card. + 'image': (optional) The image associated with the card. } App registration and user authentication @@ -202,6 +222,13 @@ methods for this are provided. .. automethod:: Mastodon.log_in .. automethod:: Mastodon.auth_request_url +Reading data: Instance +----------------------- +This function allows you to fetch information associated with the +current instance. + +.. automethod:: Mastodon.instance + Reading data: Timelines ----------------------- This function allows you to access the timelines a logged in @@ -221,6 +248,7 @@ These functions allow you to get information about single statuses. .. automethod:: Mastodon.status_context .. automethod:: Mastodon.status_reblogged_by .. automethod:: Mastodon.status_favourited_by +.. automethod:: Mastodon.status_card Reading data: Notifications --------------------------- @@ -238,10 +266,14 @@ their relationships. .. automethod:: Mastodon.account_statuses .. automethod:: Mastodon.account_following .. automethod:: Mastodon.account_followers -.. automethod:: Mastodon.follows .. automethod:: Mastodon.account_relationships .. automethod:: Mastodon.account_search +Reading data: Follows +--------------------- + +.. automethod:: Mastodon.follows + Reading data: Searching ----------------------- This function allows you to search for content. @@ -257,6 +289,14 @@ muted or blocked by the logged in user. .. automethod:: Mastodon.mutes .. automethod:: Mastodon.blocks +Reading data: Reports +------------------------------ +These functions allow you to retrieve information about reports filed +by the authenticated user, and file a report against a user. + +.. automethod:: Mastodon.reports +.. automethod:: Mastodon.report + Reading data: Favourites ------------------------ This function allows you to get information about statuses favourited @@ -295,6 +335,7 @@ These functions allow you to interact with other accounts: To (un)follow and .. automethod:: Mastodon.account_unblock .. automethod:: Mastodon.account_mute .. automethod:: Mastodon.account_unmute +.. automethod:: Mastodon.account_update_credentials Writing data: Follow requests ----------------------------- @@ -322,4 +363,4 @@ These functions allow access to the streaming API. .. _Mastodon: https://github.com/Gargron/mastodon .. _Mastodon flagship instance: http://mastodon.social/ -.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API \ No newline at end of file +.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API From 1deca1c5f6907912a13e4df92b567421f5618d33 Mon Sep 17 00:00:00 2001 From: Alex McGivern Date: Wed, 26 Apr 2017 13:12:39 +0100 Subject: [PATCH 3/5] updated github urls for masto --- docs/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index ee94166..adc2a89 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -361,6 +361,6 @@ These functions allow access to the streaming API. .. automethod:: Mastodon.hashtag_stream -.. _Mastodon: https://github.com/Gargron/mastodon +.. _Mastodon: https://github.com/tootsuite/mastodon .. _Mastodon flagship instance: http://mastodon.social/ -.. _Mastodon api docs: https://github.com/Gargron/mastodon/wiki/API +.. _Mastodon api docs: https://github.com/tootsuite/documentation/ From 973182cda07bc64545523b2ae0940c6f170c6db6 Mon Sep 17 00:00:00 2001 From: Alex McGivern Date: Wed, 26 Apr 2017 23:13:49 +0100 Subject: [PATCH 4/5] account_update_credentials uses PATCH, not POST --- mastodon/Mastodon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 2e557e4..a32241b 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -646,7 +646,7 @@ class Mastodon: 'avatar' and 'header' are PNG images encoded in base64. """ params = self.__generate_params(locals()) - return self.__api_request('POST', '/api/v1/accounts/update_credentials', params) + return self.__api_request('PATCH', '/api/v1/accounts/update_credentials', params) ### # Writing data: Reports From 91e5388daef3f66b546726dcd57e84682df40a8f Mon Sep 17 00:00:00 2001 From: Alex McGivern Date: Thu, 27 Apr 2017 00:21:32 +0100 Subject: [PATCH 5/5] added content-type hint fixed POST parameters for reports added handling for PATCH requests added check for missing Date header to prevent errors when testing against Puma --- mastodon/Mastodon.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index a32241b..3b00f37 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -643,7 +643,8 @@ class Mastodon: 'note' is the user's bio. - 'avatar' and 'header' are PNG images encoded in base64. + 'avatar' and 'header' are images encoded in base64, prepended by a content-type + (for example: 'data:image/png;base64,iVBORw0KGgoAAAA[...]') """ params = self.__generate_params(locals()) return self.__api_request('PATCH', '/api/v1/accounts/update_credentials', params) @@ -651,7 +652,7 @@ class Mastodon: ### # Writing data: Reports ### - def report(self, id, toots, comment): + def report(self, account_id, status_ids, comment): """ Report a user to the admin. @@ -813,6 +814,9 @@ class Mastodon: if method == 'POST': response_object = requests.post(self.api_base_url + endpoint, data = params, headers = headers, files = files, timeout = self.request_timeout) + if method == 'PATCH': + response_object = requests.patch(self.api_base_url + endpoint, data = params, headers = headers, files = files, timeout = self.request_timeout) + if method == 'DELETE': response_object = requests.delete(self.api_base_url + endpoint, data = params, headers = headers, files = files, timeout = self.request_timeout) except Exception as e: @@ -848,11 +852,12 @@ class Mastodon: self.ratelimit_reset = self.__datetime_to_epoch(ratelimit_reset_datetime) # Adjust server time to local clock - server_time_datetime = dateutil.parser.parse(response_object.headers['Date']) - server_time = self.__datetime_to_epoch(server_time_datetime) - server_time_diff = time.time() - server_time - self.ratelimit_reset += server_time_diff - self.ratelimit_lastcall = time.time() + if 'Date' in response_object.headers: + server_time_datetime = dateutil.parser.parse(response_object.headers['Date']) + server_time = self.__datetime_to_epoch(server_time_datetime) + server_time_diff = time.time() - server_time + self.ratelimit_reset += server_time_diff + self.ratelimit_lastcall = time.time() except Exception as e: raise MastodonRatelimitError("Rate limit time calculations failed: %s" % e)