kopia lustrzana https://github.com/halcy/Mastodon.py
add grouped notifications
rodzic
861d1c68d5
commit
2fde93fd3c
|
@ -43,6 +43,8 @@ v2.0.0 (IN PROGRESS)
|
||||||
* Add `instance_domain_blocks`
|
* Add `instance_domain_blocks`
|
||||||
* Add notification policy and requests (`notifications_policy`, `update_notifications_policy`, `notifications_requests`, `notification_request`, `accept_notification_request`, `reject_notification_request`, `notifications_merged`, `accept_multiple_notification_requests`, `dismiss_multiple_notification_requests`)
|
* Add notification policy and requests (`notifications_policy`, `update_notifications_policy`, `notifications_requests`, `notification_request`, `accept_notification_request`, `reject_notification_request`, `notifications_merged`, `accept_multiple_notification_requests`, `dismiss_multiple_notification_requests`)
|
||||||
* Add `instance_languages`
|
* Add `instance_languages`
|
||||||
|
* Add notification grouping (`grouped_notifications`, `grouped_notification`, `dismiss_grouped_notification`, `grouped_notification_accounts`, `unread_grouped_notifications_count`)
|
||||||
|
|
||||||
|
|
||||||
v1.8.1
|
v1.8.1
|
||||||
------
|
------
|
||||||
|
|
|
@ -5,7 +5,7 @@ Notifications and filtering
|
||||||
|
|
||||||
Notifications
|
Notifications
|
||||||
-------------
|
-------------
|
||||||
This function allows you to get information about a user's notifications as well as to clear all or some notifications and to mark conversations as read.
|
These functions allow you to get information about a user's notifications as well as to clear all or some notifications and to mark conversations as read.
|
||||||
|
|
||||||
Reading
|
Reading
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
@ -19,6 +19,16 @@ Writing
|
||||||
.. automethod:: Mastodon.conversations_read
|
.. automethod:: Mastodon.conversations_read
|
||||||
|
|
||||||
|
|
||||||
|
Grouped notifications
|
||||||
|
---------------------
|
||||||
|
This is the more modern notification API, which delivers notifications grouped.
|
||||||
|
|
||||||
|
.. automethod:: Mastodon.grouped_notifications
|
||||||
|
.. automethod:: Mastodon.grouped_notification
|
||||||
|
.. automethod:: Mastodon.dismiss_grouped_notification
|
||||||
|
.. automethod:: Mastodon.grouped_notification_accounts
|
||||||
|
.. automethod:: Mastodon.unread_grouped_notifications_count
|
||||||
|
|
||||||
Source filtering for notifications
|
Source filtering for notifications
|
||||||
----------------------------------
|
----------------------------------
|
||||||
These functions allow you to get information about source filters as well as to create and update filters, and
|
These functions allow you to get information about source filters as well as to create and update filters, and
|
||||||
|
|
|
@ -85,7 +85,8 @@ class Mastodon():
|
||||||
return try_cast_recurse(return_type, value)
|
return try_cast_recurse(return_type, value)
|
||||||
|
|
||||||
def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None,
|
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, override_type=None):
|
do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False, lang_override=None, override_type=None,
|
||||||
|
force_pagination=False):
|
||||||
"""
|
"""
|
||||||
Internal API request helper.
|
Internal API request helper.
|
||||||
|
|
||||||
|
@ -274,8 +275,8 @@ class Mastodon():
|
||||||
response = response_object.content
|
response = response_object.content
|
||||||
|
|
||||||
# Parse link headers
|
# Parse link headers
|
||||||
if isinstance(response, list) and 'Link' in response_object.headers and response_object.headers['Link'] != "":
|
if isinstance(response, list) or force_pagination and 'Link' in response_object.headers and response_object.headers['Link'] != "":
|
||||||
if not isinstance(response, PaginatableList):
|
if not isinstance(response, PaginatableList) and not force_pagination:
|
||||||
response = PaginatableList(response)
|
response = PaginatableList(response)
|
||||||
tmp_urls = requests.utils.parse_header_links(response_object.headers['Link'].rstrip('>').replace('>,<', ',<'))
|
tmp_urls = requests.utils.parse_header_links(response_object.headers['Link'].rstrip('>').replace('>,<', ',<'))
|
||||||
for url in tmp_urls:
|
for url in tmp_urls:
|
||||||
|
|
|
@ -3,7 +3,7 @@ from mastodon.errors import MastodonIllegalArgumentError
|
||||||
from mastodon.utility import api_version
|
from mastodon.utility import api_version
|
||||||
|
|
||||||
from mastodon.internals import Mastodon as Internals
|
from mastodon.internals import Mastodon as Internals
|
||||||
from mastodon.return_types import Notification, IdType, PaginatableList, Account, UnreadNotificationsCount, NotificationPolicy, NotificationRequest
|
from mastodon.return_types import Notification, IdType, PaginatableList, Account, UnreadNotificationsCount, NotificationPolicy, NotificationRequest, GroupedNotificationsResults, NonPaginatableList
|
||||||
from typing import Union, Optional, List
|
from typing import Union, Optional, List
|
||||||
|
|
||||||
class Mastodon(Internals):
|
class Mastodon(Internals):
|
||||||
|
@ -183,3 +183,66 @@ class Mastodon(Internals):
|
||||||
"""
|
"""
|
||||||
result = self.__api_request('GET', '/api/v1/notifications/requests/merged', override_type = dict)
|
result = self.__api_request('GET', '/api/v1/notifications/requests/merged', override_type = dict)
|
||||||
return result["merged"]
|
return result["merged"]
|
||||||
|
|
||||||
|
##
|
||||||
|
# Grouped notifications
|
||||||
|
##
|
||||||
|
@api_version("4.3.0", "4.3.0")
|
||||||
|
def grouped_notifications(self, max_id: Optional[IdType] = None, since_id: Optional[IdType] = None,
|
||||||
|
min_id: Optional[IdType] = None, limit: Optional[int] = None,
|
||||||
|
types: Optional[List[str]] = None, exclude_types: Optional[List[str]] = None,
|
||||||
|
account_id: Optional[Union[Account, IdType]] = None,
|
||||||
|
expand_accounts: Optional[str] = "partial_avatars", grouped_types: Optional[List[str]] = None,
|
||||||
|
include_filtered: Optional[bool] = None) -> GroupedNotificationsResults:
|
||||||
|
"""
|
||||||
|
Fetch grouped notifications for the user. Requires scope `read:notifications`.
|
||||||
|
|
||||||
|
For base parameters, see `notifications()`.
|
||||||
|
|
||||||
|
`grouped_types` controls which notication types can be grouped together - all, if not specified.
|
||||||
|
NB: "all" here means favourite, follow and reblog - other types are not groupable and are returned
|
||||||
|
individually (with a unique group key) always.
|
||||||
|
|
||||||
|
Pass `include_filtered=True` to include filtered notifications in the response.
|
||||||
|
|
||||||
|
Pass `expand_accounts="full"` to include full account details in the response, or "partial_avatars" to
|
||||||
|
include a smaller set of account details (in the `partial_accounts` field) for some (but not all - the most
|
||||||
|
recent account triggering a notification is always returned in full) of the included accounts.
|
||||||
|
The default is partial_avatars.
|
||||||
|
"""
|
||||||
|
params = self.__generate_params(locals())
|
||||||
|
return self.__api_request('GET', '/api/v2/notifications', params, force_pagination=True)
|
||||||
|
|
||||||
|
@api_version("4.3.0", "4.3.0")
|
||||||
|
def grouped_notification(self, group_key: str) -> GroupedNotificationsResults:
|
||||||
|
"""
|
||||||
|
Fetch details of a single grouped notification by its group key. Requires scope `read:notifications`.
|
||||||
|
"""
|
||||||
|
return self.__api_request('GET', f'/api/v2/notifications/{group_key}')
|
||||||
|
|
||||||
|
@api_version("4.3.0", "4.3.0")
|
||||||
|
def dismiss_grouped_notification(self, group_key: str) -> None:
|
||||||
|
"""
|
||||||
|
Dismiss a single grouped notification. Requires scope `write:notifications`.
|
||||||
|
"""
|
||||||
|
self.__api_request('POST', f'/api/v2/notifications/{group_key}/dismiss')
|
||||||
|
|
||||||
|
@api_version("4.3.0", "4.3.0")
|
||||||
|
def grouped_notification_accounts(self, group_key: str) -> NonPaginatableList[Account]:
|
||||||
|
"""
|
||||||
|
Fetch accounts associated with a grouped notification. Requires scope `write:notifications`.
|
||||||
|
"""
|
||||||
|
return self.__api_request('GET', f'/api/v2/notifications/{group_key}/accounts')
|
||||||
|
|
||||||
|
@api_version("4.3.0", "4.3.0")
|
||||||
|
def unread_grouped_notifications_count(self, limit: Optional[int] = None,
|
||||||
|
types: Optional[List[str]] = None, exclude_types: Optional[List[str]] = None,
|
||||||
|
account_id: Optional[Union[Account, IdType]] = None,
|
||||||
|
grouped_types: Optional[List[str]] = None) -> int:
|
||||||
|
"""
|
||||||
|
Fetch the count of unread grouped notifications. Requires scope `read:notifications`.
|
||||||
|
|
||||||
|
For parameters, see `notifications()` and `grouped_notifications()`.
|
||||||
|
"""
|
||||||
|
params = self.__generate_params(locals())
|
||||||
|
return self.__api_request('GET', '/api/v2/notifications/unread_count', params, override_type=dict)["count"]
|
||||||
|
|
|
@ -29,7 +29,8 @@ class Mastodon(Internals):
|
||||||
def markers_get(self, timeline: Union[str, List[str]] = ["home"]) -> Dict[str, Marker]:
|
def markers_get(self, timeline: Union[str, List[str]] = ["home"]) -> Dict[str, Marker]:
|
||||||
"""
|
"""
|
||||||
Get the last-read-location markers for the specified timelines. Valid timelines
|
Get the last-read-location markers for the specified timelines. Valid timelines
|
||||||
are the same as in :ref:`timeline() <timeline()>`
|
are `home` (the home timeline) and `notifications` (the notifications timeline,
|
||||||
|
affects which notifications are considered read).
|
||||||
|
|
||||||
Note that despite the singular name, `timeline` can be a list.
|
Note that despite the singular name, `timeline` can be a list.
|
||||||
|
|
||||||
|
@ -52,6 +53,9 @@ class Mastodon(Internals):
|
||||||
"""
|
"""
|
||||||
Set the "last read" marker(s) for the given timeline(s) to the given id(s)
|
Set the "last read" marker(s) for the given timeline(s) to the given id(s)
|
||||||
|
|
||||||
|
Valid timelines are `home` (the home timeline) and `notifications` (the notifications timeline,
|
||||||
|
affects which notifications are considered read).
|
||||||
|
|
||||||
Note that if you give an invalid timeline name, this will silently do nothing.
|
Note that if you give an invalid timeline name, this will silently do nothing.
|
||||||
|
|
||||||
Returns a dict with the updated markers, keyed by timeline name.
|
Returns a dict with the updated markers, keyed by timeline name.
|
||||||
|
|
|
@ -6330,6 +6330,22 @@ class GroupedNotificationsResults(AttribAccessDict):
|
||||||
* 4.3.0: added
|
* 4.3.0: added
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
_pagination_next: "Optional[PaginationInfo]"
|
||||||
|
"""
|
||||||
|
Information about the next page of results. Added here as a special case to allow for pagination of the lists inside of this object. (optional)
|
||||||
|
|
||||||
|
Version history:
|
||||||
|
* 4.3.0: added
|
||||||
|
"""
|
||||||
|
|
||||||
|
_pagination_prev: "Optional[PaginationInfo]"
|
||||||
|
"""
|
||||||
|
Information about the previous page of results. Added here as a special case to allow for pagination of the lists inside of this object. (optional)
|
||||||
|
|
||||||
|
Version history:
|
||||||
|
* 4.3.0: added
|
||||||
|
"""
|
||||||
|
|
||||||
_version = "4.3.0"
|
_version = "4.3.0"
|
||||||
|
|
||||||
class PartialAccountWithAvatar(AttribAccessDict):
|
class PartialAccountWithAvatar(AttribAccessDict):
|
||||||
|
|
|
@ -11,8 +11,9 @@ from mastodon.internals import Mastodon as Internals
|
||||||
|
|
||||||
from mastodon.versions import parse_version_string, max_version, api_version
|
from mastodon.versions import parse_version_string, max_version, api_version
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional, Union, Dict
|
||||||
from mastodon.return_types import PaginatableList, PaginationInfo
|
from mastodon.return_types import PaginatableList, PaginationInfo, PaginatableList
|
||||||
|
from mastodon.types_base import Entity
|
||||||
|
|
||||||
# Class level:
|
# Class level:
|
||||||
class Mastodon(Internals):
|
class Mastodon(Internals):
|
||||||
|
@ -118,7 +119,7 @@ class Mastodon(Internals):
|
||||||
###
|
###
|
||||||
# Pagination
|
# Pagination
|
||||||
###
|
###
|
||||||
def fetch_next(self, previous_page: PaginatableList) -> Optional[PaginatableList]:
|
def fetch_next(self, previous_page: Union[PaginatableList[Entity], Entity, Dict]) -> Optional[Union[PaginatableList[Entity], Entity]]:
|
||||||
"""
|
"""
|
||||||
Fetches the next page of results of a paginated request. Pass in the
|
Fetches the next page of results of a paginated request. Pass in the
|
||||||
previous page in its entirety, or the pagination information dict
|
previous page in its entirety, or the pagination information dict
|
||||||
|
@ -143,9 +144,12 @@ class Mastodon(Internals):
|
||||||
endpoint = params['_pagination_endpoint']
|
endpoint = params['_pagination_endpoint']
|
||||||
del params['_pagination_endpoint']
|
del params['_pagination_endpoint']
|
||||||
|
|
||||||
return self.__api_request(method, endpoint, params)
|
force_pagination = False
|
||||||
|
if not isinstance(previous_page, list):
|
||||||
|
force_pagination = True
|
||||||
|
return self.__api_request(method, endpoint, params, force_pagination=force_pagination, override_type=type(previous_page))
|
||||||
|
|
||||||
def fetch_previous(self, next_page: PaginatableList) -> Optional[PaginatableList]:
|
def fetch_previous(self, next_page: Union[PaginatableList[Entity], Entity, Dict]) -> Optional[Union[PaginatableList[Entity], Entity]]:
|
||||||
"""
|
"""
|
||||||
Fetches the previous page of results of a paginated request. Pass in the
|
Fetches the previous page of results of a paginated request. Pass in the
|
||||||
previous page in its entirety, or the pagination information dict
|
previous page in its entirety, or the pagination information dict
|
||||||
|
@ -170,9 +174,12 @@ class Mastodon(Internals):
|
||||||
endpoint = params['_pagination_endpoint']
|
endpoint = params['_pagination_endpoint']
|
||||||
del params['_pagination_endpoint']
|
del params['_pagination_endpoint']
|
||||||
|
|
||||||
return self.__api_request(method, endpoint, params)
|
force_pagination = False
|
||||||
|
if not isinstance(next_page, list):
|
||||||
|
force_pagination = True
|
||||||
|
return self.__api_request(method, endpoint, params, force_pagination=force_pagination, override_type=type(next_page))
|
||||||
|
|
||||||
def fetch_remaining(self, first_page):
|
def fetch_remaining(self, first_page: PaginatableList[Entity]) -> PaginatableList[Entity]:
|
||||||
"""
|
"""
|
||||||
Fetches all the remaining pages of a paginated request starting from a
|
Fetches all the remaining pages of a paginated request starting from a
|
||||||
first page and returns the entire set of results (including the first page
|
first page and returns the entire set of results (including the first page
|
||||||
|
@ -180,6 +187,9 @@ class Mastodon(Internals):
|
||||||
|
|
||||||
Be careful, as this might generate a lot of requests, depending on what you are
|
Be careful, as this might generate a lot of requests, depending on what you are
|
||||||
fetching, and might cause you to run into rate limits very quickly.
|
fetching, and might cause you to run into rate limits very quickly.
|
||||||
|
|
||||||
|
Does not currently work with grouped notifications, please deal with those
|
||||||
|
yourself, for now.
|
||||||
"""
|
"""
|
||||||
first_page = copy.deepcopy(first_page)
|
first_page = copy.deepcopy(first_page)
|
||||||
|
|
||||||
|
|
|
@ -9462,7 +9462,7 @@
|
||||||
"is_nullable": false
|
"is_nullable": false
|
||||||
},
|
},
|
||||||
"notification_groups": {
|
"notification_groups": {
|
||||||
"description": "The grouped notifications themselves.",
|
"description": "The grouped notifications themselves. Is actually in fact paginatable, but via the parent object.",
|
||||||
"enum": null,
|
"enum": null,
|
||||||
"version_history": [["4.3.0", "added"]],
|
"version_history": [["4.3.0", "added"]],
|
||||||
"field_type": "NonPaginatableList",
|
"field_type": "NonPaginatableList",
|
||||||
|
@ -9470,6 +9470,26 @@
|
||||||
"field_structuretype": null,
|
"field_structuretype": null,
|
||||||
"is_optional": false,
|
"is_optional": false,
|
||||||
"is_nullable": false
|
"is_nullable": false
|
||||||
|
},
|
||||||
|
"_pagination_next": {
|
||||||
|
"description": "Information about the next page of results. Added here as a special case to allow for pagination of the lists inside of this object.",
|
||||||
|
"enum": null,
|
||||||
|
"version_history": [["4.3.0", "added"]],
|
||||||
|
"field_type": "PaginationInfo",
|
||||||
|
"field_subtype": null,
|
||||||
|
"field_structuretype": null,
|
||||||
|
"is_optional": true,
|
||||||
|
"is_nullable": false
|
||||||
|
},
|
||||||
|
"_pagination_prev": {
|
||||||
|
"description": "Information about the previous page of results. Added here as a special case to allow for pagination of the lists inside of this object.",
|
||||||
|
"enum": null,
|
||||||
|
"version_history": [["4.3.0", "added"]],
|
||||||
|
"field_type": "PaginationInfo",
|
||||||
|
"field_subtype": null,
|
||||||
|
"field_structuretype": null,
|
||||||
|
"is_optional": true,
|
||||||
|
"is_nullable": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,563 @@
|
||||||
|
interactions:
|
||||||
|
- request:
|
||||||
|
body: status=Testing+grouped+notifications%21&visibility=public
|
||||||
|
headers:
|
||||||
|
Accept:
|
||||||
|
- '*/*'
|
||||||
|
Accept-Encoding:
|
||||||
|
- gzip, deflate
|
||||||
|
Authorization:
|
||||||
|
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Content-Length:
|
||||||
|
- '57'
|
||||||
|
Content-Type:
|
||||||
|
- application/x-www-form-urlencoded
|
||||||
|
User-Agent:
|
||||||
|
- tests/v311
|
||||||
|
method: POST
|
||||||
|
uri: http://localhost:3000/api/v1/statuses
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":0,"edited_at":null,"favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"content":"\u003cp\u003eTesting
|
||||||
|
grouped notifications!\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":1,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '1505'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"06fb25c4bf01795b2054bd152aeb8ef4"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.05, sql.active_record;dur=11.42, cache_generate.active_support;dur=3.55,
|
||||||
|
cache_write.active_support;dur=0.15, instantiation.active_record;dur=0.54,
|
||||||
|
start_processing.action_controller;dur=0.00, transaction.active_record;dur=4.50,
|
||||||
|
render.active_model_serializers;dur=15.64, process_action.action_controller;dur=63.46
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '298'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T21:00:00.763790Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- d4d9d0c4-0e3e-44ad-a7f8-c2b1dfa7efa3
|
||||||
|
X-Runtime:
|
||||||
|
- '0.093185'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
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
|
||||||
|
Content-Length:
|
||||||
|
- '0'
|
||||||
|
User-Agent:
|
||||||
|
- tests/v311
|
||||||
|
method: POST
|
||||||
|
uri: http://localhost:3000/api/v1/statuses/114009357138722264/favourite
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":1,"edited_at":null,"favourited":true,"reblogged":false,"muted":false,"bookmarked":false,"content":"\u003cp\u003eTesting
|
||||||
|
grouped notifications!\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":1,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '1489'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"3ac631610fb82fcfb82750e1f7adccf9"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.06, sql.active_record;dur=7.67, cache_generate.active_support;dur=3.17,
|
||||||
|
cache_write.active_support;dur=0.13, instantiation.active_record;dur=0.67,
|
||||||
|
start_processing.action_controller;dur=0.00, transaction.active_record;dur=6.21,
|
||||||
|
render.active_model_serializers;dur=16.68, process_action.action_controller;dur=47.95
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.828950Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- 6ec29c54-8c91-4b9f-9c88-275a236b5775
|
||||||
|
X-Runtime:
|
||||||
|
- '0.063835'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
- request:
|
||||||
|
body: null
|
||||||
|
headers:
|
||||||
|
Accept:
|
||||||
|
- '*/*'
|
||||||
|
Accept-Encoding:
|
||||||
|
- gzip, deflate
|
||||||
|
Authorization:
|
||||||
|
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_3
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Content-Length:
|
||||||
|
- '0'
|
||||||
|
User-Agent:
|
||||||
|
- tests/v311
|
||||||
|
method: POST
|
||||||
|
uri: http://localhost:3000/api/v1/statuses/114009357138722264/favourite
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":2,"edited_at":null,"favourited":true,"reblogged":false,"muted":false,"bookmarked":false,"content":"\u003cp\u003eTesting
|
||||||
|
grouped notifications!\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":1,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '1489'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"bfcc74cd78fb7eb5b1351bb0f8e1a5fb"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.05, sql.active_record;dur=7.32, cache_generate.active_support;dur=3.52,
|
||||||
|
cache_write.active_support;dur=0.14, instantiation.active_record;dur=0.68,
|
||||||
|
start_processing.action_controller;dur=0.00, transaction.active_record;dur=5.76,
|
||||||
|
render.active_model_serializers;dur=14.78, process_action.action_controller;dur=48.71
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.926662Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- f0f16848-82d0-457c-876c-9aa3e56deed7
|
||||||
|
X-Runtime:
|
||||||
|
- '0.063387'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
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/v2/notifications?limit=10&expand_accounts=partial_avatars
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"accounts":[{"id":"114009019470060047","username":"mastodonpy_test_2","acct":"mastodonpy_test_2","display_name":"","locked":false,"bot":false,"discoverable":true,"indexable":true,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test_2","uri":"http://localhost:3000/users/mastodonpy_test_2","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":0,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]}],"partial_accounts":[{"id":"114009019031846737","acct":"admin","locked":false,"bot":false,"url":"http://localhost:3000/@admin","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png"}],"statuses":[{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":2,"edited_at":null,"favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"content":"\u003cp\u003eTesting
|
||||||
|
grouped notifications!\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":1,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}],"notification_groups":[{"group_key":"favourite-114009357138722264-483234","notifications_count":2,"type":"favourite","most_recent_notification_id":190,"page_min_id":"190","page_max_id":"190","latest_page_notification_at":"2025-02-15T18:38:52.146Z","sample_account_ids":["114009019470060047","114009019031846737"],"status_id":"114009357138722264"}]}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '2901'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"e5e803ebda94a4f2c5aeb551c6ecd9ea"
|
||||||
|
Link:
|
||||||
|
- <http://localhost:3000/api/v2/notifications?limit=10&max_id=190>; rel="next",
|
||||||
|
<http://localhost:3000/api/v2/notifications?limit=10&min_id=190>; rel="prev"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.10, sql.active_record;dur=9.10, cache_generate.active_support;dur=2.97,
|
||||||
|
cache_write.active_support;dur=0.15, instantiation.active_record;dur=1.04,
|
||||||
|
start_processing.action_controller;dur=0.00, cache_fetch_hit.active_support;dur=0.00,
|
||||||
|
render.active_model_serializers;dur=5.52, process_action.action_controller;dur=58.12
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.028981Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- fae9562c-f5be-4da1-af05-181bb7dd30f3
|
||||||
|
X-Runtime:
|
||||||
|
- '0.073893'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
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/v2/notifications/favourite-114009357138722264-483234
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"accounts":[{"id":"114009019470060047","username":"mastodonpy_test_2","acct":"mastodonpy_test_2","display_name":"","locked":false,"bot":false,"discoverable":true,"indexable":true,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test_2","uri":"http://localhost:3000/users/mastodonpy_test_2","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":0,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},{"id":"114009019031846737","username":"admin","acct":"admin","display_name":"","locked":false,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@admin","uri":"http://localhost:3000/users/admin","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":5,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[{"id":"3","name":"Owner","color":""}],"fields":[]}],"statuses":[{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":2,"edited_at":null,"favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"content":"\u003cp\u003eTesting
|
||||||
|
grouped notifications!\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":1,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}],"notification_groups":[{"group_key":"favourite-114009357138722264-483234","notifications_count":2,"type":"favourite","most_recent_notification_id":190,"sample_account_ids":["114009019470060047","114009019031846737"],"status_id":"114009357138722264"}]}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '3295'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"b4015be5d4c161ff654954b9a12091f7"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.15, sql.active_record;dur=4.10, cache_generate.active_support;dur=2.80,
|
||||||
|
cache_write.active_support;dur=0.13, instantiation.active_record;dur=1.19,
|
||||||
|
start_processing.action_controller;dur=0.00, cache_fetch_hit.active_support;dur=0.01,
|
||||||
|
render.active_model_serializers;dur=27.82, process_action.action_controller;dur=49.35
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.158661Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- a0c00eab-c12d-4e1e-a03e-0c10eeab8de2
|
||||||
|
X-Runtime:
|
||||||
|
- '0.063807'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
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/v2/notifications/favourite-114009357138722264-483234/accounts
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '[{"id":"114009019470060047","username":"mastodonpy_test_2","acct":"mastodonpy_test_2","display_name":"","locked":false,"bot":false,"discoverable":true,"indexable":true,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test_2","uri":"http://localhost:3000/users/mastodonpy_test_2","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":0,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},{"id":"114009019031846737","username":"admin","acct":"admin","display_name":"","locked":false,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@admin","uri":"http://localhost:3000/users/admin","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":5,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[{"id":"3","name":"Owner","color":""}],"fields":[]}]'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '1512'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"fb8e14dd97709a52f5a45c9d4e447a24"
|
||||||
|
Link:
|
||||||
|
- <http://localhost:3000/api/v2/notifications/favourite-114009357138722264-483234/accounts?min_id=190>;
|
||||||
|
rel="prev"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.08, sql.active_record;dur=1.64, cache_generate.active_support;dur=1.47,
|
||||||
|
cache_write.active_support;dur=0.11, instantiation.active_record;dur=0.60,
|
||||||
|
start_processing.action_controller;dur=0.01, cache_fetch_hit.active_support;dur=0.00,
|
||||||
|
render.active_model_serializers;dur=3.89, process_action.action_controller;dur=27.45
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.295492Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- 0e34fa26-6d71-4c7d-aeec-8eee17c493fb
|
||||||
|
X-Runtime:
|
||||||
|
- '0.056571'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
- request:
|
||||||
|
body: null
|
||||||
|
headers:
|
||||||
|
Accept:
|
||||||
|
- '*/*'
|
||||||
|
Accept-Encoding:
|
||||||
|
- gzip, deflate
|
||||||
|
Authorization:
|
||||||
|
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Content-Length:
|
||||||
|
- '0'
|
||||||
|
User-Agent:
|
||||||
|
- tests/v311
|
||||||
|
method: POST
|
||||||
|
uri: http://localhost:3000/api/v2/notifications/favourite-114009357138722264-483234/dismiss
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '2'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"44136fa355b3678a1146ad16f7e8649e"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.02, sql.active_record;dur=7.02, cache_generate.active_support;dur=0.95,
|
||||||
|
cache_write.active_support;dur=0.08, instantiation.active_record;dur=0.45,
|
||||||
|
start_processing.action_controller;dur=0.00, transaction.active_record;dur=7.46,
|
||||||
|
render.active_model_serializers;dur=0.03, process_action.action_controller;dur=30.07
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.366862Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- 512683b1-cf01-497d-8e16-e853aae9d9c2
|
||||||
|
X-Runtime:
|
||||||
|
- '0.044774'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
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/v2/notifications?limit=10&expand_accounts=partial_avatars
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"accounts":[],"partial_accounts":[],"statuses":[],"notification_groups":[]}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '76'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"eda10f9499b0acd6b521397b2c54e608"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.04, sql.active_record;dur=1.65, cache_generate.active_support;dur=2.39,
|
||||||
|
cache_write.active_support;dur=0.11, instantiation.active_record;dur=0.25,
|
||||||
|
start_processing.action_controller;dur=0.00, render.active_model_serializers;dur=0.26,
|
||||||
|
process_action.action_controller;dur=22.95
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '300'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '299'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T18:40:00.414885Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- a16d6183-ac0e-4bb2-bb6d-4415200bb284
|
||||||
|
X-Runtime:
|
||||||
|
- '0.037428'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
- request:
|
||||||
|
body: null
|
||||||
|
headers:
|
||||||
|
Accept:
|
||||||
|
- '*/*'
|
||||||
|
Accept-Encoding:
|
||||||
|
- gzip, deflate
|
||||||
|
Authorization:
|
||||||
|
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN
|
||||||
|
Connection:
|
||||||
|
- keep-alive
|
||||||
|
Content-Length:
|
||||||
|
- '0'
|
||||||
|
User-Agent:
|
||||||
|
- tests/v311
|
||||||
|
method: DELETE
|
||||||
|
uri: http://localhost:3000/api/v1/statuses/114009357138722264
|
||||||
|
response:
|
||||||
|
body:
|
||||||
|
string: '{"id":"114009357138722264","created_at":"2025-02-15T18:38:51.731Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"ja","uri":"http://localhost:3000/users/mastodonpy_test/statuses/114009357138722264","url":"http://localhost:3000/@mastodonpy_test/114009357138722264","replies_count":0,"reblogs_count":0,"favourites_count":2,"edited_at":null,"favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"text":"Testing
|
||||||
|
grouped notifications!","filtered":[],"reblog":null,"application":{"name":"Mastodon.py
|
||||||
|
test suite","website":null},"account":{"id":"114009019326978043","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"indexable":false,"group":false,"created_at":"2025-02-15T00:00:00.000Z","note":"","url":"http://localhost:3000/@mastodonpy_test","uri":"http://localhost:3000/users/mastodonpy_test","avatar":"http://localhost:3000/avatars/original/missing.png","avatar_static":"http://localhost:3000/avatars/original/missing.png","header":"http://localhost:3000/headers/original/missing.png","header_static":"http://localhost:3000/headers/original/missing.png","followers_count":0,"following_count":0,"statuses_count":0,"last_status_at":"2025-02-15","hide_collections":null,"noindex":false,"emojis":[],"roles":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}'
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
- private, no-store
|
||||||
|
Content-Length:
|
||||||
|
- '1475'
|
||||||
|
Content-Security-Policy:
|
||||||
|
- default-src 'none'; frame-ancestors 'none'; form-action 'none'
|
||||||
|
Content-Type:
|
||||||
|
- application/json; charset=utf-8
|
||||||
|
ETag:
|
||||||
|
- W/"61fa0386cc5fd7fcd2b5cbd617ebfb55"
|
||||||
|
Referrer-Policy:
|
||||||
|
- strict-origin-when-cross-origin
|
||||||
|
Server-Timing:
|
||||||
|
- cache_read.active_support;dur=0.05, sql.active_record;dur=6.22, cache_generate.active_support;dur=2.83,
|
||||||
|
cache_write.active_support;dur=0.17, instantiation.active_record;dur=0.75,
|
||||||
|
start_processing.action_controller;dur=0.00, transaction.active_record;dur=3.13,
|
||||||
|
render.active_model_serializers;dur=13.62, process_action.action_controller;dur=41.39
|
||||||
|
X-Content-Type-Options:
|
||||||
|
- nosniff
|
||||||
|
X-Frame-Options:
|
||||||
|
- SAMEORIGIN
|
||||||
|
X-Permitted-Cross-Domain-Policies:
|
||||||
|
- none
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
- '30'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
- '29'
|
||||||
|
X-RateLimit-Reset:
|
||||||
|
- '2025-02-15T19:00:00.460335Z'
|
||||||
|
X-Request-Id:
|
||||||
|
- d68ff7be-46c4-4ed4-8f9b-14792c89aa98
|
||||||
|
X-Runtime:
|
||||||
|
- '0.059427'
|
||||||
|
X-XSS-Protection:
|
||||||
|
- '0'
|
||||||
|
vary:
|
||||||
|
- Authorization, Origin
|
||||||
|
status:
|
||||||
|
code: 200
|
||||||
|
message: OK
|
||||||
|
version: 1
|
|
@ -143,3 +143,70 @@ def test_notification_requests_accept(api, api2):
|
||||||
for status in posted:
|
for status in posted:
|
||||||
api.status_delete(status)
|
api.status_delete(status)
|
||||||
api2.update_notifications_policy(for_not_following="accept", for_not_followers="accept", for_new_accounts="accept", for_limited_accounts="accept", for_private_mentions="accept")
|
api2.update_notifications_policy(for_not_following="accept", for_not_followers="accept", for_new_accounts="accept", for_limited_accounts="accept", for_private_mentions="accept")
|
||||||
|
|
||||||
|
@pytest.mark.vcr()
|
||||||
|
def test_grouped_notifications(api, api2, api3):
|
||||||
|
try:
|
||||||
|
status = api.status_post("Testing grouped notifications!", visibility="public")
|
||||||
|
api2.status_favourite(status["id"])
|
||||||
|
api3.status_favourite(status["id"])
|
||||||
|
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
grouped_notifs = api.grouped_notifications(limit=10, expand_accounts="partial_avatars")
|
||||||
|
assert grouped_notifs
|
||||||
|
assert hasattr(grouped_notifs, "_pagination_next")
|
||||||
|
assert hasattr(grouped_notifs, "_pagination_prev")
|
||||||
|
|
||||||
|
group_keys = [group.group_key for group in grouped_notifs.notification_groups]
|
||||||
|
assert any("favourite" in key or "reblog" in key for key in group_keys), "Expected a grouped notification"
|
||||||
|
|
||||||
|
group_key = group_keys[0] # Take first group
|
||||||
|
single_grouped_notif = api.grouped_notification(group_key)
|
||||||
|
assert single_grouped_notif
|
||||||
|
assert single_grouped_notif.notification_groups[0].group_key == group_key
|
||||||
|
|
||||||
|
accounts = api.grouped_notification_accounts(group_key)
|
||||||
|
assert isinstance(accounts, list)
|
||||||
|
assert len(accounts) > 0
|
||||||
|
|
||||||
|
partial_accounts = [acc for acc in accounts if hasattr(acc, 'avatar_static')]
|
||||||
|
assert len(partial_accounts) > 0, "Expected at least one partial account"
|
||||||
|
|
||||||
|
api.dismiss_grouped_notification(group_key)
|
||||||
|
|
||||||
|
updated_grouped_notifs = api.grouped_notifications(limit=10)
|
||||||
|
updated_group_keys = [group.group_key for group in updated_grouped_notifs.notification_groups]
|
||||||
|
assert group_key not in updated_group_keys, "Dismissed notification still appears"
|
||||||
|
finally:
|
||||||
|
api.status_delete(status["id"])
|
||||||
|
|
||||||
|
@pytest.mark.vcr()
|
||||||
|
def test_grouped_notification_pagination(api, api2):
|
||||||
|
try:
|
||||||
|
# Post 10 statuses that mention api
|
||||||
|
posted = []
|
||||||
|
api_name = api.account_verify_credentials().username
|
||||||
|
for i in range(10):
|
||||||
|
posted.append(api2.status_post(f"@{api_name} hey how you doing - {i}!", visibility="public"))
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
grouped_notifs = api.grouped_notifications(limit=5, expand_accounts="full")
|
||||||
|
assert len(grouped_notifs.notification_groups) == 5
|
||||||
|
assert grouped_notifs._pagination_next
|
||||||
|
assert grouped_notifs._pagination_prev
|
||||||
|
|
||||||
|
# Fetch next page
|
||||||
|
next_notifs = api.fetch_next(grouped_notifs)
|
||||||
|
assert len(next_notifs.notification_groups) == 5
|
||||||
|
assert next_notifs._pagination_next
|
||||||
|
assert next_notifs._pagination_prev
|
||||||
|
|
||||||
|
# Fetch previous page
|
||||||
|
prev_notifs = api.fetch_previous(next_notifs)
|
||||||
|
assert len(prev_notifs.notification_groups) == 5
|
||||||
|
assert prev_notifs._pagination_next
|
||||||
|
assert prev_notifs._pagination_prev
|
||||||
|
finally:
|
||||||
|
for status in posted:
|
||||||
|
api2.status_delete(status["id"])
|
Ładowanie…
Reference in New Issue