diff --git a/TODO.md b/TODO.md index e0b504a..d5e16bd 100644 --- a/TODO.md +++ b/TODO.md @@ -43,11 +43,11 @@ 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 +* [x] Add category and rule_ids params to POST /api/v1/reports IN REST API * [ ] 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 diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index a4fe768..d0b3606 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -373,10 +373,9 @@ class Mastodon: If no other `User-Agent` is specified, "mastodonpy" will be used. """ - if api_base_url is None: - raise MastodonIllegalArgumentError("API base URL is required.") - 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 @@ -417,9 +416,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 @@ -428,8 +427,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: @@ -439,10 +437,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 @@ -994,7 +996,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. @@ -1573,7 +1575,7 @@ class Mastodon: 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 `status dicts`_, sorted by the instances's trending algorithm, + Returns a list of `toot dicts`_, sorted by the instances's trending algorithm, descending. """ params = self.__generate_params(locals()) @@ -1690,6 +1692,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') ### @@ -2530,7 +2534,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"]) @@ -2696,18 +2700,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: @@ -3297,6 +3308,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 ### diff --git a/tests/cassettes/test_admin_trends.yaml b/tests/cassettes/test_admin_trends.yaml new file mode 100644 index 0000000..a471f98 --- /dev/null +++ b/tests/cassettes/test_admin_trends.yaml @@ -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 diff --git a/tests/cassettes/test_revoke.yaml b/tests/cassettes/test_revoke.yaml index b56655e..bc75494 100644 --- a/tests/cassettes/test_revoke.yaml +++ b/tests/cassettes/test_revoke.yaml @@ -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: diff --git a/tests/test_admin.py b/tests/test_admin.py index f62b96b..6a72ed7 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -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 diff --git a/tests/test_auth.py b/tests/test_auth.py index a14b4e7..8a2337b 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -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)