From 5215c2242dd7b87418a7c10781c2b10b35d86f46 Mon Sep 17 00:00:00 2001 From: halcy Date: Sun, 13 Nov 2022 18:39:56 +0200 Subject: Fix some things in streaming and admin API for 3.3.0 support --- mastodon/Mastodon.py | 29 ++++++++++++++++++++++++++--- mastodon/streaming.py | 48 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 10 deletions(-) (limited to 'mastodon') diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 7db5fba..e84df6d 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -303,7 +303,7 @@ class Mastodon: api_base_url=None, debug_requests=False, ratelimit_method="wait", ratelimit_pacefactor=1.1, request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None, - version_check_mode = "created", session=None, feature_set="mainline", user_agent=None): + version_check_mode = "created", session=None, feature_set="mainline", user_agent="mastodonpy"): """ Create a new API wrapper instance based on the given `client_secret` and `client_id`. If you give a `client_id` and it is not a file, you must also give a secret. If you specify an @@ -349,10 +349,12 @@ class Mastodon: Details are documented in the functions that provide such functionality. Currently supported feature sets are `mainline`, `fedibird` and `pleroma`. - For some mastodon-instances a `User-Agent` header is needed. This can be set by parameter `user_agent`. From now - `create_app()` stores the application name into the client secret file. If `client_id` points to this file, + For some mastodon-instances a `User-Agent` header is needed. This can be set by parameter `user_agent`. Starting from + Mastodon.py 1.5.2 `create_app()` stores the application name into the client secret file. If `client_id` points to this file, the app name will be used as `User-Agent` header as default. It's possible to modify old secret files and append a client app name to use it as a `User-Agent` name. + + If no other user agent is specified, "mastodonpy" will be used. """ self.api_base_url = None if not api_base_url is None: @@ -2870,6 +2872,26 @@ class Mastodon: id = self.__unpack_id(id) return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsuspend'.format(id)) + @api_version("3.3.0", "3.3.0", __DICT_VERSION_ADMIN_ACCOUNT) + def admin_account_delete(self, id): + """ + Delete a local user account. + + The deleted accounts `admin account dict`_. + """ + id = self.__unpack_id(id) + return self.__api_request('DELETE', '/api/v1/admin/accounts/{0}'.format(id)) + + @api_version("3.3.0", "3.3.0", __DICT_VERSION_ADMIN_ACCOUNT) + def admin_account_unsensitive(self, id): + """ + Unmark an account as force-sensitive. + + Returns the updated `admin account dict`_. + """ + id = self.__unpack_id(id) + return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsensitive'.format(id)) + @api_version("2.9.1", "2.9.1", "2.9.1") def admin_account_moderate(self, id, action=None, report_id=None, warning_preset_id=None, text=None, send_email_notification=True): """ @@ -2879,6 +2901,7 @@ class Mastodon: * "disable" - for a local user, disable login. * "silence" - hide the users posts from all public timelines. * "suspend" - irreversibly delete all the users posts, past and future. + * "sensitive" - forcce an accounts media visibility to always be sensitive. If no action is specified, the user is only issued a warning. Specify the id of a report as `report_id` to close the report with this moderation action as the resolution. diff --git a/mastodon/streaming.py b/mastodon/streaming.py index ceb61ea..65acba8 100644 --- a/mastodon/streaming.py +++ b/mastodon/streaming.py @@ -5,6 +5,11 @@ https://github.com/tootsuite/mastodon/blob/master/docs/Using-the-API/Streaming-A import json import six +try: + from inspect import signature +except: + pass + from mastodon import Mastodon from mastodon.Mastodon import MastodonMalformedEventError, MastodonNetworkError, MastodonReadTimeout from requests.exceptions import ChunkedEncodingError, ReadTimeout @@ -16,10 +21,15 @@ class StreamListener(object): Mastodon.hashtag_stream().""" def on_update(self, status): - """A new status has appeared! 'status' is the parsed JSON dictionary + """A new status has appeared. 'status' is the parsed JSON dictionary describing the status.""" pass + def on_status_update(self, status): + """A status has been edited. 'status' is the parsed JSON dictionary + describing the updated status.""" + pass + def on_notification(self, notification): """A new notification. 'notification' is the parsed JSON dictionary describing the notification.""" @@ -55,6 +65,7 @@ class StreamListener(object): self.on_abort(exception) raise exception + def handle_heartbeat(self): """The server has sent us a keep-alive message. This callback may be useful to carry out periodic housekeeping tasks, or just to confirm @@ -135,6 +146,10 @@ class StreamListener(object): try: name = event['event'] data = event['data'] + try: + for_stream = json.loads(event['stream']) + except: + for_stream = None payload = json.loads(data, object_hook = Mastodon._Mastodon__json_hooks) except KeyError as err: exception = MastodonMalformedEventError('Missing field', err.args[0], event) @@ -152,15 +167,29 @@ class StreamListener(object): exception, err ) - # New mastodon API also supports event names with dots: + # New mastodon API also supports event names with dots, + # specifically, status_update. handler_name = 'on_' + name.replace('.', '_') + # A generic way to handle unknown events to make legacy code more stable for future changes handler = getattr(self, handler_name, self.on_unknown_event) - if handler != self.on_unknown_event: - handler(payload) + try: + handler_args = list(signature(handler).parameters) + except: + handler_args = handler.__code__.co_varnames[:handler.__code__.co_argcount] + + # The "for_stream" is right now only theoretical - it's only supported on websocket, + # and we do not support websocket based multiplexed streams (yet). + if "for_stream" in handler_args: + if handler != self.on_unknown_event: + handler(payload, for_stream) + else: + handler(name, payload, for_stream) else: - handler(name, payload) - + if handler != self.on_unknown_event: + handler(payload) + else: + handler(name, payload) class CallbackStreamListener(StreamListener): """ @@ -169,7 +198,7 @@ class CallbackStreamListener(StreamListener): Define an unknown_event_handler for new Mastodon API events. If not, the listener will raise an error on new, not handled, events from the API. """ - def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None): + def __init__(self, update_handler = None, local_update_handler = None, delete_handler = None, notification_handler = None, conversation_handler = None, unknown_event_handler = None, status_update_handler = None): super(CallbackStreamListener, self).__init__() self.update_handler = update_handler self.local_update_handler = local_update_handler @@ -177,6 +206,7 @@ class CallbackStreamListener(StreamListener): self.notification_handler = notification_handler self.conversation_handler = conversation_handler self.unknown_event_handler = unknown_event_handler + self.status_update_handler = status_update_handler def on_update(self, status): if self.update_handler != None: @@ -210,3 +240,7 @@ class CallbackStreamListener(StreamListener): exception = MastodonMalformedEventError('Bad event type', name) self.on_abort(exception) raise exception + + def on_status_update(self, status): + if self.status_update_handler != None: + self.status_update_handler(status) \ No newline at end of file -- cgit v1.2.3