kopia lustrzana https://github.com/halcy/Mastodon.py
commit
99514e50d1
|
@ -2,6 +2,15 @@ A note on versioning: This librarys major version will grow with the APIs
|
|||
version number. Breaking changes will be indicated by a change in the minor
|
||||
(or major) version number, and will generally be avoided.
|
||||
|
||||
v1.8.0 (in progress)
|
||||
--------------------
|
||||
* BREAKING CHANGE: Switch the base URL to None, throw an error when no base url is passed. Having mastosoc as default was sensible when there were only three mastodon servers. It is not sensible now and trips people up constantly.
|
||||
* Fix an issue with the fix for the Pleroma date bug (thanks adbenitez)
|
||||
* Add trending APIs (`trending_tags`, `trending_statuses`, `trending_links`, `admin_trending_tags`, `admin_trending_statuses`, `admin_trending_links`)
|
||||
* Add `lang` parameter and document what it does properly.
|
||||
* Add `category` and `rule_ids` to `reports`
|
||||
* This too isn't really a changelog entry but in the same vein as the last post, thank you Claire and Gargron for clarifying many things about the API when asked.
|
||||
|
||||
v1.7.0
|
||||
------
|
||||
* Cleaned code up a bit (thanks eumiro)
|
||||
|
|
8
TODO.md
8
TODO.md
|
@ -43,12 +43,12 @@ Refer to mastodon changelog and API docs for details when implementing, add or m
|
|||
-----
|
||||
* [x] Add support for incoming edited posts
|
||||
* [x] Add notifications for posts deleted by moderators <- by email. not actually API relevant.
|
||||
* [ ] Add explore page with trending posts and links
|
||||
* [x] Add explore page with trending posts and links
|
||||
* [ ] Add graphs and retention metrics to admin dashboard
|
||||
* [ ] Add GET /api/v1/accounts/familiar_followers to REST API
|
||||
* [ ] Add POST /api/v1/accounts/:id/remove_from_followers to REST API
|
||||
* [ ] Add category and rule_ids params to POST /api/v1/reports IN REST API
|
||||
* [ ] Add global lang param to REST API
|
||||
* [x] Add category and rule_ids params to POST /api/v1/reports IN REST API
|
||||
* [x] Add global lang param to REST API
|
||||
* [x] Add types param to GET /api/v1/notifications in REST API
|
||||
* [x] Add notifications for moderators about new sign-ups
|
||||
* [ ] v2 admin account api
|
||||
|
@ -66,4 +66,4 @@ General improvements that would be good to do before doing another release:
|
|||
* [x] Fix the CI
|
||||
* [ ] Get test coverage like, real high
|
||||
* [x] Add all those streaming events??
|
||||
* [ ] Document return values
|
||||
* [ ] Document return values (skipping this for a bit to then do it at the end with tooling)
|
||||
|
|
|
@ -1089,6 +1089,9 @@ Reading data: Searching
|
|||
Reading data: Trends
|
||||
--------------------
|
||||
|
||||
.. automethod:: Mastodon.trending_tags
|
||||
.. automethod:: Mastodon.trending_statuses
|
||||
.. automethod:: Mastodon.trending_links
|
||||
.. automethod:: Mastodon.trends
|
||||
|
||||
Reading data: Mutes and blocks
|
||||
|
@ -1440,6 +1443,10 @@ have admin: scopes attached with a lot of care, but be extra careful with those
|
|||
.. automethod:: Mastodon.admin_report_reopen
|
||||
.. automethod:: Mastodon.admin_report_resolve
|
||||
|
||||
.. automethod:: Mastodon.admin_trending_tags
|
||||
.. automethod:: Mastodon.admin_trending_statuses
|
||||
.. automethod:: Mastodon.admin_trending_links
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
Mastodon.py contains work by a large number of contributors, many of which have
|
||||
|
|
|
@ -167,7 +167,6 @@ class Mastodon:
|
|||
If anything is unclear, check the official API docs at
|
||||
https://github.com/mastodon/documentation/blob/master/content/en/client/intro.md
|
||||
"""
|
||||
__DEFAULT_BASE_URL = 'https://mastodon.social'
|
||||
__DEFAULT_TIMEOUT = 300
|
||||
__DEFAULT_STREAM_TIMEOUT = 300
|
||||
__DEFAULT_STREAM_RECONNECT_WAIT_SEC = 5
|
||||
|
@ -260,17 +259,17 @@ class Mastodon:
|
|||
###
|
||||
@staticmethod
|
||||
def create_app(client_name, scopes=__DEFAULT_SCOPES, redirect_uris=None, website=None, to_file=None,
|
||||
api_base_url=__DEFAULT_BASE_URL, request_timeout=__DEFAULT_TIMEOUT, session=None):
|
||||
api_base_url=None, request_timeout=__DEFAULT_TIMEOUT, session=None):
|
||||
"""
|
||||
Create a new app with given `client_name` and `scopes` (The basic scopes are "read", "write", "follow" and "push"
|
||||
- more granular scopes are available, please refer to Mastodon documentation for which).
|
||||
- more granular scopes are available, please refer to Mastodon documentation for which) on the instance given
|
||||
by `api_base_url`.
|
||||
|
||||
Specify `redirect_uris` if you want users to be redirected to a certain page after authenticating in an OAuth flow.
|
||||
You can specify multiple URLs by passing a list. Note that if you wish to use OAuth authentication with redirects,
|
||||
the redirect URI must be one of the URLs specified here.
|
||||
|
||||
Specify `to_file` to persist your app's info to a file so you can use it in the constructor.
|
||||
Specify `api_base_url` if you want to register an app on an instance different from the flagship one.
|
||||
Specify `website` to give a website for your app.
|
||||
|
||||
Specify `session` with a requests.Session for it to be used instead of the default. This can be
|
||||
|
@ -282,6 +281,8 @@ class Mastodon:
|
|||
|
||||
Returns `client_id` and `client_secret`, both as strings.
|
||||
"""
|
||||
if api_base_url is None:
|
||||
raise MastodonIllegalArgumentError("API base URL is required.")
|
||||
api_base_url = Mastodon.__protocolize(api_base_url)
|
||||
|
||||
request_data = {
|
||||
|
@ -299,12 +300,10 @@ class Mastodon:
|
|||
if website is not None:
|
||||
request_data['website'] = website
|
||||
if session:
|
||||
ret = session.post(api_base_url + '/api/v1/apps',
|
||||
data=request_data, timeout=request_timeout)
|
||||
ret = session.post(api_base_url + '/api/v1/apps', data=request_data, timeout=request_timeout)
|
||||
response = ret.json()
|
||||
else:
|
||||
response = requests.post(
|
||||
api_base_url + '/api/v1/apps', data=request_data, timeout=request_timeout)
|
||||
response = requests.post(api_base_url + '/api/v1/apps', data=request_data, timeout=request_timeout)
|
||||
response = response.json()
|
||||
except Exception as e:
|
||||
raise MastodonNetworkError("Could not complete request: %s" % e)
|
||||
|
@ -321,17 +320,15 @@ class Mastodon:
|
|||
###
|
||||
# Authentication, including constructor
|
||||
###
|
||||
def __init__(self, client_id=None, client_secret=None, access_token=None,
|
||||
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="mastodonpy"):
|
||||
def __init__(self, client_id=None, client_secret=None, access_token=None, 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="mastodonpy", lang=None):
|
||||
"""
|
||||
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
|
||||
`access_token` then you don't need to specify a `client_id`. It is allowed to specify
|
||||
neither - in this case, you will be restricted to only using endpoints that do not
|
||||
require authentication. If a file is given as `client_id`, client ID, secret and
|
||||
Create a new API wrapper instance based on the given `client_secret` and `client_id` on the
|
||||
instance given by `api_base_url`. If you give a `client_id` and it is not a file, you must
|
||||
also give a secret. If you specify an `access_token` then you don't need to specify a `client_id`.
|
||||
It is allowed to specify neither - in this case, you will be restricted to only using endpoints
|
||||
that do not require authentication. If a file is given as `client_id`, client ID, secret and
|
||||
base url are read from that file.
|
||||
|
||||
You can also specify an `access_token`, directly or as a file (as written by `log_in()`_). If
|
||||
|
@ -347,10 +344,6 @@ class Mastodon:
|
|||
even in "wait" and "pace" mode, requests can still fail due to network or other problems! Also
|
||||
note that "pace" and "wait" are NOT thread safe.
|
||||
|
||||
Specify `api_base_url` if you wish to talk to an instance other than the flagship one. When
|
||||
reading from client id or access token files as written by Mastodon.py 1.5.0 or larger,
|
||||
this can be omitted.
|
||||
|
||||
By default, a timeout of 300 seconds is used for all requests. If you wish to change this,
|
||||
pass the desired timeout (in seconds) as `request_timeout`.
|
||||
|
||||
|
@ -376,12 +369,15 @@ class Mastodon:
|
|||
the app name will be used as `User-Agent` header as default. It is possible to modify old secret files and append
|
||||
a client app name to use it as a `User-Agent` name.
|
||||
|
||||
`lang` can be used to change the locale Mastodon will use to generate responses. Valid parameters are all ISO 639-1 (two letter)
|
||||
or for a language that has none, 639-3 (three letter) language codes. This affects some error messages (those related to validation) and
|
||||
trends. You can change the language using `set_language()`_.
|
||||
|
||||
If no other `User-Agent` is specified, "mastodonpy" will be used.
|
||||
"""
|
||||
self.api_base_url = None
|
||||
if api_base_url is not None:
|
||||
self.api_base_url = Mastodon.__protocolize(api_base_url)
|
||||
|
||||
self.api_base_url = api_base_url
|
||||
if self.api_base_url is not None:
|
||||
self.api_base_url = self.__protocolize(self.api_base_url)
|
||||
self.client_id = client_id
|
||||
self.client_secret = client_secret
|
||||
self.access_token = access_token
|
||||
|
@ -389,7 +385,7 @@ class Mastodon:
|
|||
self.ratelimit_method = ratelimit_method
|
||||
self._token_expired = datetime.datetime.now()
|
||||
self._refresh_token = None
|
||||
|
||||
|
||||
self.__logged_in_id = None
|
||||
|
||||
self.ratelimit_limit = 300
|
||||
|
@ -412,6 +408,9 @@ class Mastodon:
|
|||
# General defined user-agent
|
||||
self.user_agent = user_agent
|
||||
|
||||
# Save language
|
||||
self.lang = lang
|
||||
|
||||
# Token loading
|
||||
if self.client_id is not None:
|
||||
if os.path.isfile(self.client_id):
|
||||
|
@ -422,9 +421,9 @@ class Mastodon:
|
|||
try_base_url = secret_file.readline().rstrip()
|
||||
if try_base_url is not None and len(try_base_url) != 0:
|
||||
try_base_url = Mastodon.__protocolize(try_base_url)
|
||||
print(self.api_base_url, try_base_url)
|
||||
if not (self.api_base_url is None or try_base_url == self.api_base_url):
|
||||
raise MastodonIllegalArgumentError(
|
||||
'Mismatch in base URLs between files and/or specified')
|
||||
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
|
||||
self.api_base_url = try_base_url
|
||||
|
||||
# With new registrations we support the 4th line to store a client_name and use it as user-agent
|
||||
|
@ -433,8 +432,7 @@ class Mastodon:
|
|||
self.user_agent = client_name.rstrip()
|
||||
else:
|
||||
if self.client_secret is None:
|
||||
raise MastodonIllegalArgumentError(
|
||||
'Specified client id directly, but did not supply secret')
|
||||
raise MastodonIllegalArgumentError('Specified client id directly, but did not supply secret')
|
||||
|
||||
if self.access_token is not None and os.path.isfile(self.access_token):
|
||||
with open(self.access_token, 'r') as token_file:
|
||||
|
@ -444,10 +442,14 @@ class Mastodon:
|
|||
if try_base_url is not None and len(try_base_url) != 0:
|
||||
try_base_url = Mastodon.__protocolize(try_base_url)
|
||||
if not (self.api_base_url is None or try_base_url == self.api_base_url):
|
||||
raise MastodonIllegalArgumentError(
|
||||
'Mismatch in base URLs between files and/or specified')
|
||||
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
|
||||
self.api_base_url = try_base_url
|
||||
|
||||
# Verify we have a base URL, protocolize
|
||||
if self.api_base_url is None:
|
||||
raise MastodonIllegalArgumentError("API base URL is required.")
|
||||
self.api_base_url = Mastodon.__protocolize(self.api_base_url)
|
||||
|
||||
if not version_check_mode in ["created", "changed", "none"]:
|
||||
raise MastodonIllegalArgumentError("Invalid version check method.")
|
||||
self.version_check_mode = version_check_mode
|
||||
|
@ -470,6 +472,13 @@ class Mastodon:
|
|||
if ratelimit_method not in ["throw", "wait", "pace"]:
|
||||
raise MastodonIllegalArgumentError("Invalid ratelimit method.")
|
||||
|
||||
def set_language(self, lang):
|
||||
"""
|
||||
Set the locale Mastodon will use to generate responses. Valid parameters are all ISO 639-1 (two letter) or, for languages that do
|
||||
not have one, 639-3 (three letter) language codes. This affects some error messages (those related to validation) and trends.
|
||||
"""
|
||||
self.lang = lang
|
||||
|
||||
def __normalize_version_string(self, version_string):
|
||||
# Split off everything after the first space, to take care of Pleromalikes so that the parser doesn't get confused in case those have a + somewhere in their version
|
||||
version_string = version_string.split(" ")[0]
|
||||
|
@ -541,24 +550,27 @@ class Mastodon:
|
|||
"""
|
||||
return Mastodon.__SUPPORTED_MASTODON_VERSION
|
||||
|
||||
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None):
|
||||
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None, lang=None):
|
||||
"""
|
||||
Returns the URL that a client needs to request an OAuth grant from the server.
|
||||
|
||||
To log in with OAuth, send your user to this URL. The user will then log in and
|
||||
get a code which you can pass to log_in.
|
||||
get a code which you can pass to `log_in()`_.
|
||||
|
||||
scopes are as in `log_in()`_, redirect_uris is where the user should be redirected to
|
||||
after authentication. Note that redirect_uris must be one of the URLs given during
|
||||
`scopes` are as in `log_in()`_, redirect_uris is where the user should be redirected to
|
||||
after authentication. Note that `redirect_uris` must be one of the URLs given during
|
||||
app registration. When using urn:ietf:wg:oauth:2.0:oob, the code is simply displayed,
|
||||
otherwise it is added to the given URL as the "code" request parameter.
|
||||
|
||||
Pass force_login if you want the user to always log in even when already logged
|
||||
into web Mastodon (i.e. when registering multiple different accounts in an app).
|
||||
|
||||
State is the oauth `state`parameter to pass to the server. It is strongly suggested
|
||||
`state` is the oauth `state` parameter to pass to the server. It is strongly suggested
|
||||
to use a random, nonguessable value (i.e. nothing meaningful and no incrementing ID)
|
||||
to preserve security guarantees. It can be left out for non-web login flows.
|
||||
|
||||
Pass an ISO 639-1 (two letter) or, for languages that do not have one, 639-3 (three letter)
|
||||
language code as `lang` to control the display language for the oauth form.
|
||||
"""
|
||||
if client_id is None:
|
||||
client_id = self.client_id
|
||||
|
@ -574,6 +586,7 @@ class Mastodon:
|
|||
params['scope'] = " ".join(scopes)
|
||||
params['force_login'] = force_login
|
||||
params['state'] = state
|
||||
params['lang'] = lang
|
||||
formatted_params = urlencode(params)
|
||||
return "".join([self.api_base_url, "/oauth/authorize?", formatted_params])
|
||||
|
||||
|
@ -675,8 +688,9 @@ class Mastodon:
|
|||
Creates a new user account with the given username, password and email. "agreement"
|
||||
must be set to true (after showing the user the instance's user agreement and having
|
||||
them agree to it), "locale" specifies the language for the confirmation email as an
|
||||
ISO 639-1 (two-letter) language code. `reason` can be used to specify why a user
|
||||
would like to join if approved-registrations mode is on.
|
||||
ISO 639-1 (two letter) or, if a language does not have one, 639-3 (three letter) language
|
||||
code. `reason` can be used to specify why a user would like to join if approved-registrations
|
||||
mode is on.
|
||||
|
||||
Does not require an access token, but does require a client grant.
|
||||
|
||||
|
@ -999,7 +1013,7 @@ class Mastodon:
|
|||
Does not require authentication for publicly visible statuses.
|
||||
|
||||
This function is deprecated as of 3.0.0 and the endpoint does not
|
||||
exist anymore - you should just use the "card" field of the status dicts
|
||||
exist anymore - you should just use the "card" field of the toot dicts
|
||||
instead. Mastodon.py will try to mimic the old behaviour, but this
|
||||
is somewhat inefficient and not guaranteed to be the case forever.
|
||||
|
||||
|
@ -1540,8 +1554,15 @@ class Mastodon:
|
|||
###
|
||||
# Reading data: Trends
|
||||
###
|
||||
@api_version("2.4.3", "3.0.0", __DICT_VERSION_HASHTAG)
|
||||
@api_version("2.4.3", "3.5.0", __DICT_VERSION_HASHTAG)
|
||||
def trends(self, limit=None):
|
||||
"""
|
||||
Alias for `trending_tags()`_
|
||||
"""
|
||||
return self.trending_tags(limit=limit)
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_HASHTAG)
|
||||
def trending_tags(self, limit=None, lang=None):
|
||||
"""
|
||||
Fetch trending-hashtag information, if the instance provides such information.
|
||||
|
||||
|
@ -1551,13 +1572,49 @@ class Mastodon:
|
|||
Does not require authentication unless locked down by the administrator.
|
||||
|
||||
Important versioning note: This endpoint does not exist for Mastodon versions
|
||||
between 2.8.0 (inclusive) and 3.0.0 (exclusive).
|
||||
between 2.8.0 (inclusive) and 3.0.0 (exclusive).
|
||||
|
||||
Pass `lang` to override the global locale parameter, which may affect trend ordering.
|
||||
|
||||
Returns a list of `hashtag dicts`_, sorted by the instance's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/trends', params)
|
||||
if self.verify_minimum_version("3.5.0", cached=True):
|
||||
# Starting 3.5.0, old version is deprecated
|
||||
return self.__api_request('GET', '/api/v1/trends/tags', params)
|
||||
else:
|
||||
return self.__api_request('GET', '/api/v1/trends', params)
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS)
|
||||
def trending_statuses(self):
|
||||
"""
|
||||
Fetch trending-status information, if the instance provides such information.
|
||||
|
||||
Specify `limit` to limit how many results are returned (the maximum number
|
||||
of results is 10, the endpoint is not paginated).
|
||||
|
||||
Pass `lang` to override the global locale parameter, which may affect trend ordering.
|
||||
|
||||
Returns a list of `toot dicts`_, sorted by the instances's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/trends/statuses', params)
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_CARD)
|
||||
def trending_links(self):
|
||||
"""
|
||||
Fetch trending-link information, if the instance provides such information.
|
||||
|
||||
Specify `limit` to limit how many results are returned (the maximum number
|
||||
of results is 10, the endpoint is not paginated).
|
||||
|
||||
Returns a list of `card dicts`_, sorted by the instances's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/trends/links', params)
|
||||
|
||||
###
|
||||
# Reading data: Lists
|
||||
|
@ -1656,6 +1713,8 @@ class Mastodon:
|
|||
Warning: This method has now finally been removed, and will not
|
||||
work on Mastodon versions 2.5.0 and above.
|
||||
"""
|
||||
if self.verify_minimum_version("2.5.0", cached=True):
|
||||
raise MastodonVersionError("API removed in Mastodon 2.5.0")
|
||||
return self.__api_request('GET', '/api/v1/reports')
|
||||
|
||||
###
|
||||
|
@ -1943,7 +2002,8 @@ class Mastodon:
|
|||
displayed.
|
||||
|
||||
Specify `language` to override automatic language detection. The parameter
|
||||
accepts all valid ISO 639-2 language codes.
|
||||
accepts all valid ISO 639-1 (2-letter) or for languages where that do not
|
||||
have one, 639-3 (three letter) language codes.
|
||||
|
||||
You can set `idempotency_key` to a value to uniquely identify an attempt
|
||||
at posting a status. Even if you call this function more than once,
|
||||
|
@ -2496,7 +2556,7 @@ class Mastodon:
|
|||
"""
|
||||
Set a note (visible to the logged in user only) for the given account.
|
||||
|
||||
Returns a `status dict`_ with the `note` updated.
|
||||
Returns a `toot dict`_ with the `note` updated.
|
||||
"""
|
||||
id = self.__unpack_id(id)
|
||||
params = self.__generate_params(locals(), ["id"])
|
||||
|
@ -2662,18 +2722,25 @@ class Mastodon:
|
|||
###
|
||||
# Writing data: Reports
|
||||
###
|
||||
@api_version("1.1.0", "2.5.0", __DICT_VERSION_REPORT)
|
||||
def report(self, account_id, status_ids=None, comment=None, forward=False):
|
||||
@api_version("1.1.0", "3.5.0", __DICT_VERSION_REPORT)
|
||||
def report(self, account_id, status_ids=None, comment=None, forward=False, category=None, rule_ids=None):
|
||||
"""
|
||||
Report statuses to the instances administrators.
|
||||
|
||||
Accepts a list of toot IDs associated with the report, and a comment.
|
||||
|
||||
Set forward to True to forward a report of a remote user to that users
|
||||
Starting with Mastodon 3.5.0, you can also pass a `category` (one out of
|
||||
"spam", "violation" or "other") and `rule_ids` (a list of rule IDs corresponding
|
||||
to the rules returned by the `instance()`_ API).
|
||||
|
||||
Set `forward` to True to forward a report of a remote user to that users
|
||||
instance as well as sending it to the instance local administrators.
|
||||
|
||||
Returns a `report dict`_.
|
||||
"""
|
||||
if category is not None and not category in ["spam", "violation", "other"]:
|
||||
raise MastodonIllegalArgumentError("Invalid report category (must be spam, violation or other)")
|
||||
|
||||
account_id = self.__unpack_id(account_id)
|
||||
|
||||
if status_ids is not None:
|
||||
|
@ -3263,6 +3330,39 @@ class Mastodon:
|
|||
id = self.__unpack_id(id)
|
||||
return self.__api_request('POST', '/api/v1/admin/reports/{0}/resolve'.format(id))
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_HASHTAG)
|
||||
def admin_trending_tags(self, limit=None):
|
||||
"""
|
||||
Admin version of `trending_tags()`_. Includes unapproved tags.
|
||||
|
||||
Returns a list of `hashtag dicts`_, sorted by the instance's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/admin/trends/tags', params)
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS)
|
||||
def admin_trending_statuses(self):
|
||||
"""
|
||||
Admin version of `trending_statuses()`_. Includes unapproved tags.
|
||||
|
||||
Returns a list of `toot dicts`_, sorted by the instance's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/admin/trends/statuses', params)
|
||||
|
||||
@api_version("3.5.0", "3.5.0", __DICT_VERSION_CARD)
|
||||
def admin_trending_links(self):
|
||||
"""
|
||||
Admin version of `trending_links()`_. Includes unapproved tags.
|
||||
|
||||
Returns a list of `card dicts`_, sorted by the instance's trending algorithm,
|
||||
descending.
|
||||
"""
|
||||
params = self.__generate_params(locals())
|
||||
return self.__api_request('GET', '/api/v1/admin/trends/links', params)
|
||||
|
||||
###
|
||||
# Push subscription crypto utilities
|
||||
###
|
||||
|
@ -3560,6 +3660,7 @@ class Mastodon:
|
|||
"""
|
||||
known_date_fields = ["created_at", "week", "day", "expires_at", "scheduled_at",
|
||||
"updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"]
|
||||
mark_delete = []
|
||||
for k, v in json_object.items():
|
||||
if k in known_date_fields:
|
||||
if v is not None:
|
||||
|
@ -3569,11 +3670,11 @@ class Mastodon:
|
|||
else:
|
||||
json_object[k] = dateutil.parser.parse(v)
|
||||
except:
|
||||
if isinstance(v, str) and len(x.strip()) == 0:
|
||||
# Pleroma bug workaround: Empty string becomes start of epoch
|
||||
json_object[k] = datetime.datetime.fromtimestamp(0)
|
||||
else:
|
||||
raise MastodonAPIError('Encountered invalid date.')
|
||||
# When we can't parse a date, we just leave the field out
|
||||
mark_delete.append(k)
|
||||
# Two step process because otherwise python gets very upset
|
||||
for k in mark_delete:
|
||||
del json_object[k]
|
||||
return json_object
|
||||
|
||||
@staticmethod
|
||||
|
@ -3626,12 +3727,20 @@ class Mastodon:
|
|||
isotime = isotime[:-2] + ":" + isotime[-2:]
|
||||
return isotime
|
||||
|
||||
def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None, do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False):
|
||||
def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None,
|
||||
do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False, lang_override=None):
|
||||
"""
|
||||
Internal API request helper.
|
||||
"""
|
||||
response = None
|
||||
remaining_wait = 0
|
||||
|
||||
# Add language to params if not None
|
||||
lang = self.lang
|
||||
if lang_override is not None:
|
||||
lang = lang_override
|
||||
if lang is not None:
|
||||
params["lang"] = lang
|
||||
|
||||
# "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it
|
||||
# would take to not hit the rate limit at that request rate.
|
||||
|
@ -3690,8 +3799,7 @@ class Mastodon:
|
|||
else:
|
||||
kwargs['data'] = params
|
||||
|
||||
response_object = self.session.request(
|
||||
method, base_url + endpoint, **kwargs)
|
||||
response_object = self.session.request(method, base_url + endpoint, **kwargs)
|
||||
except Exception as e:
|
||||
raise MastodonNetworkError(
|
||||
"Could not complete request: %s" % e)
|
||||
|
@ -3734,15 +3842,14 @@ class Mastodon:
|
|||
|
||||
# Handle response
|
||||
if self.debug_requests:
|
||||
print('Mastodon: Response received with code ' +
|
||||
str(response_object.status_code) + '.')
|
||||
print('Mastodon: Response received with code ' + str(response_object.status_code) + '.')
|
||||
print('response headers: ' + str(response_object.headers))
|
||||
print('Response text content: ' + str(response_object.text))
|
||||
|
||||
if not response_object.ok:
|
||||
try:
|
||||
response = response_object.json(
|
||||
object_hook=self.__json_hooks)
|
||||
response = response_object.json(object_hook=self.__json_hooks)
|
||||
print(response)
|
||||
if isinstance(response, dict) and 'error' in response:
|
||||
error_msg = response['error']
|
||||
elif isinstance(response, str):
|
||||
|
@ -3796,8 +3903,7 @@ class Mastodon:
|
|||
|
||||
if parse:
|
||||
try:
|
||||
response = response_object.json(
|
||||
object_hook=self.__json_hooks)
|
||||
response = response_object.json(object_hook=self.__json_hooks)
|
||||
except:
|
||||
raise MastodonAPIError(
|
||||
"Could not parse response as JSON, response code was %s, "
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/admin/trends/tags
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-riTO9qzezJtfpKUBo5FfRw=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 7f790ab8-9fba-4fd4-b1d1-32f98f057ced
|
||||
X-Runtime:
|
||||
- '0.019713'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/admin/trends/statuses
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-LJrdU51JLzwv175738dEzQ=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 247300e7-df10-49fa-81b7-5ee6fd5d82a4
|
||||
X-Runtime:
|
||||
- '0.027509'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/admin/trends/links
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-UsGPkqqgkgw3xXRrC/rS6Q=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- f9838813-fc1a-455b-8ee4-6c4e38f62be0
|
||||
X-Runtime:
|
||||
- '0.018125'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/admin/trends/tags?limit=5
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-yIFkCE0nhCUfZnXpKkcTiQ=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 51da904e-4de6-49d8-8680-b02a8dce3feb
|
||||
X-Runtime:
|
||||
- '0.008825'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
File diff suppressed because one or more lines are too long
|
@ -19,14 +19,14 @@ interactions:
|
|||
response:
|
||||
body:
|
||||
string: '{"access_token":"__MASTODON_PY_TEST_ACCESS_TOKEN_3","token_type":"Bearer","scope":"read
|
||||
write follow push","created_at":1669069472}'
|
||||
write follow push","created_at":1669078552}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-2hAAmzxVIF2o8Dybbe/Nlw=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-qgSt4nG9WHHoLhv8/BTiNA=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -36,7 +36,7 @@ interactions:
|
|||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"2f20b949ed12ddfc15861ec448b5551f"
|
||||
- W/"64a8679bd2f3d37be418066de7284ddd"
|
||||
Pragma:
|
||||
- no-cache
|
||||
Referrer-Policy:
|
||||
|
@ -54,9 +54,9 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 8e26834c-db67-484e-bf41-80e3a1e48c83
|
||||
- f7be8646-6edb-4018-89b2-525917883907
|
||||
X-Runtime:
|
||||
- '0.056343'
|
||||
- '0.072228'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
|
@ -79,14 +79,14 @@ interactions:
|
|||
uri: http://localhost:3000/api/v1/instance/
|
||||
response:
|
||||
body:
|
||||
string: '{"uri":"localhost:3000","title":"Mastodon","short_description":"","description":"","email":"","version":"4.0.0rc2","urls":{"streaming_api":"ws://localhost:4000"},"stats":{"user_count":4,"status_count":1,"domain_count":0},"thumbnail":"http://localhost:3000/packs/media/images/preview-6399aebd96ccf025654e2977454f168f.png","languages":["en"],"registrations":true,"approval_required":false,"invites_enabled":true,"configuration":{"accounts":{"max_featured_tags":10},"statuses":{"max_characters":500,"max_media_attachments":4,"characters_reserved_per_url":23},"media_attachments":{"supported_mime_types":["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"],"image_size_limit":10485760,"image_matrix_limit":16777216,"video_size_limit":41943040,"video_frame_rate_limit":60,"video_matrix_limit":2304000},"polls":{"max_options":4,"max_characters_per_option":50,"min_expiration":300,"max_expiration":2629746}},"contact_account":null,"rules":[]}'
|
||||
string: '{"uri":"localhost:3000","title":"Mastodon","short_description":"","description":"","email":"","version":"4.0.0rc2","urls":{"streaming_api":"ws://localhost:4000"},"stats":{"user_count":4,"status_count":8,"domain_count":0},"thumbnail":"http://localhost:3000/packs/media/images/preview-6399aebd96ccf025654e2977454f168f.png","languages":["en"],"registrations":true,"approval_required":false,"invites_enabled":true,"configuration":{"accounts":{"max_featured_tags":10},"statuses":{"max_characters":500,"max_media_attachments":4,"characters_reserved_per_url":23},"media_attachments":{"supported_mime_types":["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"],"image_size_limit":10485760,"image_matrix_limit":16777216,"video_size_limit":41943040,"video_frame_rate_limit":60,"video_matrix_limit":2304000},"polls":{"max_options":4,"max_characters_per_option":50,"min_expiration":300,"max_expiration":2629746}},"contact_account":null,"rules":[]}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- max-age=180, public
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-p/U3iDcksaJMkQ5IvZDsGQ=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-Xujah3tRsHYiM+FbWsiFuA=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -96,9 +96,9 @@ interactions:
|
|||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Mon, 21 Nov 2022 20:24:59 GMT
|
||||
- Thu, 24 Nov 2022 21:56:42 GMT
|
||||
ETag:
|
||||
- W/"bf317ffab393d8d1da7195269f28968a"
|
||||
- W/"b3134b9b6dd4c58f0150831d75c86c06"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
|
@ -114,9 +114,9 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 1d68749b-1782-4ee2-b0b4-f3b08b1253eb
|
||||
- 902f84f2-1256-449b-8c98-e593b8b72998
|
||||
X-Runtime:
|
||||
- '0.029627'
|
||||
- '0.042336'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
|
@ -150,7 +150,7 @@ interactions:
|
|||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-DWtDMY1MqGERclXgCGbr0Q=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-WT+/lb3ulLnfgMU4/kyt6A=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -176,9 +176,9 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- a63c3472-347e-48f5-8a11-4e5b6ebf4836
|
||||
- 8c35a1e3-0ad8-4035-bb05-0795e74bace4
|
||||
X-Runtime:
|
||||
- '0.025417'
|
||||
- '0.015637'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
|
@ -210,7 +210,7 @@ interactions:
|
|||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-8Wq3rXCQa6b3gM8cbtEXVQ=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-YJJZ0jnA7xjMKXR0QxnZpg=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -239,14 +239,74 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 220822bd-2303-424b-96d7-babf8edfc5b9
|
||||
- 0a52d3a9-ad38-4fe9-8fd4-91e90d3180c5
|
||||
X-Runtime:
|
||||
- '0.543121'
|
||||
- '0.648647'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_3
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- mastodonpy
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/instance/
|
||||
response:
|
||||
body:
|
||||
string: '{"uri":"localhost:3000","title":"Mastodon","short_description":"","description":"","email":"","version":"4.0.0rc2","urls":{"streaming_api":"ws://localhost:4000"},"stats":{"user_count":4,"status_count":8,"domain_count":0},"thumbnail":"http://localhost:3000/packs/media/images/preview-6399aebd96ccf025654e2977454f168f.png","languages":["en"],"registrations":true,"approval_required":false,"invites_enabled":true,"configuration":{"accounts":{"max_featured_tags":10},"statuses":{"max_characters":500,"max_media_attachments":4,"characters_reserved_per_url":23},"media_attachments":{"supported_mime_types":["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"],"image_size_limit":10485760,"image_matrix_limit":16777216,"video_size_limit":41943040,"video_frame_rate_limit":60,"video_matrix_limit":2304000},"polls":{"max_options":4,"max_characters_per_option":50,"min_expiration":300,"max_expiration":2629746}},"contact_account":null,"rules":[]}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- max-age=180, public
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-F1GvF0zbODWtYZVC3JI4wA=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Thu, 24 Nov 2022 21:56:43 GMT
|
||||
ETag:
|
||||
- W/"b3134b9b6dd4c58f0150831d75c86c06"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 2bf6c22d-2f68-45a4-bd92-389a130454b4
|
||||
X-Runtime:
|
||||
- '0.015512'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: status=illegal+access+detected
|
||||
headers:
|
||||
|
@ -254,6 +314,8 @@ interactions:
|
|||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_3
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
|
@ -261,19 +323,19 @@ interactions:
|
|||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
- mastodonpy
|
||||
method: POST
|
||||
uri: http://localhost:3000/api/v1/statuses
|
||||
response:
|
||||
body:
|
||||
string: '{"error":"The access token is invalid"}'
|
||||
string: "{\"error\":\"\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u306F\u53D6\u308A\u6D88\u3055\u308C\u3066\u3044\u307E\u3059\"}"
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-fMWth9zD7qWcG79MyycwRQ=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-VHNNI4iV+hIATnI9wOKj0w=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -291,8 +353,7 @@ interactions:
|
|||
Vary:
|
||||
- Accept, Origin
|
||||
WWW-Authenticate:
|
||||
- Bearer realm="Doorkeeper", error="invalid_token", error_description="The access
|
||||
token is invalid"
|
||||
- "Bearer realm=\"Doorkeeper\", error=\"invalid_token\", error_description=\"\xE3\x82\xA2\xE3\x82\xAF\xE3\x82\xBB\xE3\x82\xB9\xE3\x83\x88\xE3\x83\xBC\xE3\x82\xAF\xE3\x83\xB3\xE3\x81\xAF\xE5\x8F\x96\xE3\x82\x8A\xE6\xB6\x88\xE3\x81\x95\xE3\x82\x8C\xE3\x81\xA6\xE3\x81\x84\xE3\x81\xBE\xE3\x81\x99\""
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
|
@ -302,9 +363,9 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 17a0fa0b-62a6-44ef-90a4-91a90dcd68c8
|
||||
- ddb03e7b-25bf-4711-93a4-74e63bf8dbc5
|
||||
X-Runtime:
|
||||
- '0.005676'
|
||||
- '0.008214'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
|
|
|
@ -13,7 +13,7 @@ interactions:
|
|||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/trends
|
||||
uri: http://localhost:3000/api/v1/trends/links
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
|
@ -23,7 +23,7 @@ interactions:
|
|||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-wweJU6CNiZOq8p6GOgvKMg=='';
|
||||
style-src ''self'' http://localhost:3000 ''nonce-7UiLUEyJEVY9JgarYKBdCg=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
|
@ -49,9 +49,9 @@ interactions:
|
|||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 04d49bc9-1ad7-48de-a189-e93e527942e0
|
||||
- 623f9c94-2540-4c4f-b0ae-1c3db0b9ca35
|
||||
X-Runtime:
|
||||
- '0.010606'
|
||||
- '0.016081'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
|
@ -0,0 +1,60 @@
|
|||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/trends/statuses
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-Qp9U6bbMsEloa3BOJP+ApA=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 9b65a082-dbab-436e-9544-9d3ceae169b0
|
||||
X-Runtime:
|
||||
- '0.022649'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
|
@ -0,0 +1,118 @@
|
|||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/trends/tags
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-x84HIusoB0oMG/yq6Q4NDg=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- e26034bb-bfdb-4f3a-bbef-9d2e51f88c14
|
||||
X-Runtime:
|
||||
- '0.029510'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||
Connection:
|
||||
- keep-alive
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: GET
|
||||
uri: http://localhost:3000/api/v1/trends/tags
|
||||
response:
|
||||
body:
|
||||
string: '[]'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-mRWh2zKUzi/z+WYqVSZD1g=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"4f53cda18c2baa0c0354bb5f9a3ecbe5"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- c1cc20bc-a0b0-4ffa-bd72-686a094e1da0
|
||||
X-Runtime:
|
||||
- '0.015007'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
|
@ -108,7 +108,14 @@ def test_admin_reports(api, api2, status):
|
|||
report2 = api2.admin_report(report)
|
||||
assert(report2)
|
||||
assert(report2.id == report.id)
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_admin_trends(api2):
|
||||
assert isinstance(api2.admin_trending_tags(), list)
|
||||
assert isinstance(api2.admin_trending_statuses(), list)
|
||||
assert isinstance(api2.admin_trending_links(), list)
|
||||
assert isinstance(api2.admin_trending_tags(limit=5), list)
|
||||
|
||||
@pytest.mark.skip(reason="reject / accept of account requests isn't really testable without modifying instance settings. anyone want to fumble those into the DB setup and write this test, please do.")
|
||||
def test_admin_accountrequests(api2):
|
||||
pass
|
||||
|
|
|
@ -34,7 +34,7 @@ def test_log_in_password(api_anonymous):
|
|||
def test_revoke(api_anonymous):
|
||||
token = api_anonymous.log_in(
|
||||
username='mastodonpy_test_2@localhost:3000',
|
||||
password='5fc638e0e53eafd9c4145b6bb852667d'
|
||||
password='5fc638e0e53eafd9c4145b6bb852667d',
|
||||
)
|
||||
api_anonymous.revoke_access_token()
|
||||
|
||||
|
@ -45,9 +45,9 @@ def test_revoke(api_anonymous):
|
|||
print(e)
|
||||
pass
|
||||
|
||||
api_revoked_token = Mastodon(access_token = token)
|
||||
api_revoked_token = Mastodon(access_token = token, api_base_url='http://localhost:3000')
|
||||
try:
|
||||
api_anonymous.toot("illegal access detected")
|
||||
api_revoked_token.toot("illegal access detected")
|
||||
assert False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
|
|
@ -8,8 +8,10 @@ def test_constructor_from_filenames(tmpdir):
|
|||
access = tmpdir.join('access')
|
||||
access.write_text(u'baz\n', 'UTF-8')
|
||||
api = Mastodon(
|
||||
str(client),
|
||||
access_token=str(access))
|
||||
str(client),
|
||||
access_token=str(access),
|
||||
api_base_url="mastodon.social"
|
||||
)
|
||||
assert api.client_id == 'foo'
|
||||
assert api.client_secret == 'bar'
|
||||
assert api.access_token == 'baz'
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import pytest
|
||||
import vcr
|
||||
from mastodon.Mastodon import MastodonAPIError
|
||||
import json
|
||||
|
||||
try:
|
||||
from mock import MagicMock
|
||||
|
@ -8,8 +10,7 @@ except ImportError:
|
|||
|
||||
def test_nonstandard_errors(api):
|
||||
response = MagicMock()
|
||||
response.json = MagicMock(return_value=
|
||||
"I am a non-standard instance and this error is a plain string.")
|
||||
response.json = MagicMock(return_value="I am a non-standard instance and this error is a plain string.")
|
||||
response.ok = False
|
||||
response.status_code = 501
|
||||
session = MagicMock()
|
||||
|
@ -19,3 +20,23 @@ def test_nonstandard_errors(api):
|
|||
with pytest.raises(MastodonAPIError):
|
||||
api.instance()
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_lang_for_errors(api):
|
||||
try:
|
||||
api.status_post("look at me i am funny shark gawr gura: " + "a" * 50000)
|
||||
except Exception as e:
|
||||
e1 = str(e)
|
||||
api.set_language("de")
|
||||
try:
|
||||
api.status_post("look at me i am funny shark gawr gura: " + "a" * 50000)
|
||||
except Exception as e:
|
||||
e2 = str(e)
|
||||
assert e1 != e2
|
||||
|
||||
def test_broken_date(api):
|
||||
dict1 = json.loads('{"uri":"icosahedron.website", "created_at": "", "edited_at": "2012-09-27"}', object_hook=api._Mastodon__json_hooks)
|
||||
dict2 = json.loads('{"uri":"icosahedron.website", "created_at": "2012-09-27", "subfield": {"edited_at": "null"}}', object_hook=api._Mastodon__json_hooks)
|
||||
assert "edited_at" in dict1
|
||||
assert not "created_at" in dict1
|
||||
assert "created_at" in dict2
|
||||
assert not "edited_at" in dict2.subfield
|
||||
|
|
|
@ -62,10 +62,6 @@ def test_nodeinfo(api):
|
|||
assert nodeinfo
|
||||
assert nodeinfo.version == '2.0'
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_trends(api):
|
||||
assert isinstance(api.trends(), list)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_directory(api):
|
||||
directory = api.directory()
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import pytest
|
||||
import time
|
||||
import vcr
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_trending_tags(api):
|
||||
tags = api.trending_tags()
|
||||
assert isinstance(tags, list)
|
||||
tags = api.trends()
|
||||
assert isinstance(tags, list)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_trending_statuses(api):
|
||||
statuses = api.trending_statuses()
|
||||
assert isinstance(statuses, list)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_trending_links(api):
|
||||
links = api.trending_links()
|
||||
assert isinstance(links, list)
|
Ładowanie…
Reference in New Issue