diff options
author | halcy <halcy@ARARAGI-KUN> | 2022-11-22 00:10:02 +0200 |
---|---|---|
committer | halcy <halcy@ARARAGI-KUN> | 2022-11-22 00:10:02 +0200 |
commit | f3d25fa19deb2caf0793d685a542509f94c2c8a9 (patch) | |
tree | 92e45bf340668cffe014d8d7df66dff2d594064a | |
parent | 6abaff55e7e78b83bd03af9f370a1256e7271b4a (diff) | |
download | mastodon.py-f3d25fa19deb2caf0793d685a542509f94c2c8a9.tar.gz |
add status editing
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | docs/index.rst | 17 | ||||
-rw-r--r-- | mastodon/Mastodon.py | 218 | ||||
-rw-r--r-- | tests/cassettes/test_status_edit.yaml | 379 | ||||
-rw-r--r-- | tests/test_status.py | 16 |
5 files changed, 549 insertions, 83 deletions
@@ -65,5 +65,5 @@ General improvements that would be good to do before doing another release: | |||
65 | * [ ] Split mastodon.py into parts in some way that makes sense, it's getting very unwieldy | 65 | * [ ] Split mastodon.py into parts in some way that makes sense, it's getting very unwieldy |
66 | * [x] Fix the CI | 66 | * [x] Fix the CI |
67 | * [ ] Get test coverage like, real high | 67 | * [ ] Get test coverage like, real high |
68 | * [ ] Add all those streaming events?? | 68 | * [x] Add all those streaming events?? |
69 | * [ ] Document return values | 69 | * [ ] Document return values |
diff --git a/docs/index.rst b/docs/index.rst index 450300e..3d52b08 100644 --- a/docs/index.rst +++ b/docs/index.rst | |||
@@ -876,6 +876,19 @@ Admin account dicts | |||
876 | 'account': # The user's account, as a standard user dict | 876 | 'account': # The user's account, as a standard user dict |
877 | } | 877 | } |
878 | 878 | ||
879 | Status edit dicts | ||
880 | ~~~~~~~~~~~~~~~~~ | ||
881 | .. _status edit dict: | ||
882 | |||
883 | .. code-block:: python | ||
884 | |||
885 | mastodonstatus_history(id)[0] | ||
886 | # Returns the following dictionary | ||
887 | { | ||
888 | TODO | ||
889 | } | ||
890 | |||
891 | |||
879 | App registration and user authentication | 892 | App registration and user authentication |
880 | ---------------------------------------- | 893 | ---------------------------------------- |
881 | Before you can use the Mastodon API, you have to register your | 894 | Before you can use the Mastodon API, you have to register your |
@@ -967,6 +980,8 @@ These functions allow you to get information about single statuses. | |||
967 | .. automethod:: Mastodon.status_reblogged_by | 980 | .. automethod:: Mastodon.status_reblogged_by |
968 | .. automethod:: Mastodon.status_favourited_by | 981 | .. automethod:: Mastodon.status_favourited_by |
969 | .. automethod:: Mastodon.status_card | 982 | .. automethod:: Mastodon.status_card |
983 | .. automethod:: Mastodon.status_history | ||
984 | .. automethod:: Mastodon.status_source | ||
970 | 985 | ||
971 | Reading data: Scheduled statuses | 986 | Reading data: Scheduled statuses |
972 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 987 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
@@ -1142,6 +1157,8 @@ interact with already posted statuses. | |||
1142 | .. automethod:: Mastodon.status_bookmark | 1157 | .. automethod:: Mastodon.status_bookmark |
1143 | .. automethod:: Mastodon.status_unbookmark | 1158 | .. automethod:: Mastodon.status_unbookmark |
1144 | .. automethod:: Mastodon.status_delete | 1159 | .. automethod:: Mastodon.status_delete |
1160 | .. automethod:: Mastodon.status_update | ||
1161 | |||
1145 | 1162 | ||
1146 | Writing data: Scheduled statuses | 1163 | Writing data: Scheduled statuses |
1147 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1164 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 2a70ce7..48b1307 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -229,30 +229,25 @@ class Mastodon: | |||
229 | __DICT_VERSION_HASHTAG = "2.3.4" | 229 | __DICT_VERSION_HASHTAG = "2.3.4" |
230 | __DICT_VERSION_EMOJI = "3.0.0" | 230 | __DICT_VERSION_EMOJI = "3.0.0" |
231 | __DICT_VERSION_RELATIONSHIP = "3.3.0" | 231 | __DICT_VERSION_RELATIONSHIP = "3.3.0" |
232 | __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version( | 232 | __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) |
233 | "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) | ||
234 | __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) | 233 | __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) |
235 | __DICT_VERSION_LIST = "2.1.0" | 234 | __DICT_VERSION_LIST = "2.1.0" |
236 | __DICT_VERSION_CARD = "3.2.0" | 235 | __DICT_VERSION_CARD = "3.2.0" |
237 | __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version( | 236 | __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) |
238 | "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) | ||
239 | __DICT_VERSION_ACTIVITY = "2.1.2" | 237 | __DICT_VERSION_ACTIVITY = "2.1.2" |
240 | __DICT_VERSION_REPORT = "2.9.1" | 238 | __DICT_VERSION_REPORT = "2.9.1" |
241 | __DICT_VERSION_PUSH = "2.4.0" | 239 | __DICT_VERSION_PUSH = "2.4.0" |
242 | __DICT_VERSION_PUSH_NOTIF = "2.4.0" | 240 | __DICT_VERSION_PUSH_NOTIF = "2.4.0" |
243 | __DICT_VERSION_FILTER = "2.4.3" | 241 | __DICT_VERSION_FILTER = "2.4.3" |
244 | __DICT_VERSION_CONVERSATION = bigger_version(bigger_version( | 242 | __DICT_VERSION_CONVERSATION = bigger_version(bigger_version("2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) |
245 | "2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) | 243 | __DICT_VERSION_SCHEDULED_STATUS = bigger_version("2.7.0", __DICT_VERSION_STATUS) |
246 | __DICT_VERSION_SCHEDULED_STATUS = bigger_version( | ||
247 | "2.7.0", __DICT_VERSION_STATUS) | ||
248 | __DICT_VERSION_PREFERENCES = "2.8.0" | 244 | __DICT_VERSION_PREFERENCES = "2.8.0" |
249 | __DICT_VERSION_ADMIN_ACCOUNT = bigger_version( | 245 | __DICT_VERSION_ADMIN_ACCOUNT = bigger_version("2.9.1", __DICT_VERSION_ACCOUNT) |
250 | "2.9.1", __DICT_VERSION_ACCOUNT) | ||
251 | __DICT_VERSION_FEATURED_TAG = "3.0.0" | 246 | __DICT_VERSION_FEATURED_TAG = "3.0.0" |
252 | __DICT_VERSION_MARKER = "3.0.0" | 247 | __DICT_VERSION_MARKER = "3.0.0" |
253 | __DICT_VERSION_REACTION = "3.1.0" | 248 | __DICT_VERSION_REACTION = "3.1.0" |
254 | __DICT_VERSION_ANNOUNCEMENT = bigger_version( | 249 | __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION) |
255 | "3.1.0", __DICT_VERSION_REACTION) | 250 | __DICT_VERSION_STATUS_EDIT = "3.5.0" |
256 | 251 | ||
257 | ### | 252 | ### |
258 | # Registering apps | 253 | # Registering apps |
@@ -1797,80 +1792,21 @@ class Mastodon: | |||
1797 | ### | 1792 | ### |
1798 | # Writing data: Statuses | 1793 | # Writing data: Statuses |
1799 | ### | 1794 | ### |
1800 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 1795 | def __status_internal(self, status, in_reply_to_id=None, media_ids=None, |
1801 | def status_post(self, status, in_reply_to_id=None, media_ids=None, | ||
1802 | sensitive=False, visibility=None, spoiler_text=None, | 1796 | sensitive=False, visibility=None, spoiler_text=None, |
1803 | language=None, idempotency_key=None, content_type=None, | 1797 | language=None, idempotency_key=None, content_type=None, |
1804 | scheduled_at=None, poll=None, quote_id=None): | 1798 | scheduled_at=None, poll=None, quote_id=None, edit=False): |
1805 | """ | ||
1806 | Post a status. Can optionally be in reply to another status and contain | ||
1807 | media. | ||
1808 | |||
1809 | `media_ids` should be a list. (If it's not, the function will turn it | ||
1810 | into one.) It can contain up to four pieces of media (uploaded via | ||
1811 | `media_post()`_). `media_ids` can also be the `media dicts`_ returned | ||
1812 | by `media_post()`_ - they are unpacked automatically. | ||
1813 | |||
1814 | The `sensitive` boolean decides whether or not media attached to the post | ||
1815 | should be marked as sensitive, which hides it by default on the Mastodon | ||
1816 | web front-end. | ||
1817 | |||
1818 | The visibility parameter is a string value and accepts any of: | ||
1819 | 'direct' - post will be visible only to mentioned users | ||
1820 | 'private' - post will be visible only to followers | ||
1821 | 'unlisted' - post will be public but not appear on the public timeline | ||
1822 | 'public' - post will be public | ||
1823 | |||
1824 | If not passed in, visibility defaults to match the current account's | ||
1825 | default-privacy setting (starting with Mastodon version 1.6) or its | ||
1826 | locked setting - private if the account is locked, public otherwise | ||
1827 | (for Mastodon versions lower than 1.6). | ||
1828 | |||
1829 | The `spoiler_text` parameter is a string to be shown as a warning before | ||
1830 | the text of the status. If no text is passed in, no warning will be | ||
1831 | displayed. | ||
1832 | |||
1833 | Specify `language` to override automatic language detection. The parameter | ||
1834 | accepts all valid ISO 639-2 language codes. | ||
1835 | |||
1836 | You can set `idempotency_key` to a value to uniquely identify an attempt | ||
1837 | at posting a status. Even if you call this function more than once, | ||
1838 | if you call it with the same `idempotency_key`, only one status will | ||
1839 | be created. | ||
1840 | |||
1841 | Pass a datetime as `scheduled_at` to schedule the toot for a specific time | ||
1842 | (the time must be at least 5 minutes into the future). If this is passed, | ||
1843 | status_post returns a `scheduled toot dict`_ instead. | ||
1844 | |||
1845 | Pass `poll` to attach a poll to the status. An appropriate object can be | ||
1846 | constructed using `make_poll()`_ . Note that as of Mastodon version | ||
1847 | 2.8.2, you can only have either media or a poll attached, not both at | ||
1848 | the same time. | ||
1849 | |||
1850 | **Specific to "pleroma" feature set:**: Specify `content_type` to set | ||
1851 | the content type of your post on Pleroma. It accepts 'text/plain' (default), | ||
1852 | 'text/markdown', 'text/html' and 'text/bbcode'. This parameter is not | ||
1853 | supported on Mastodon servers, but will be safely ignored if set. | ||
1854 | |||
1855 | **Specific to "fedibird" feature set:**: The `quote_id` parameter is | ||
1856 | a non-standard extension that specifies the id of a quoted status. | ||
1857 | |||
1858 | Returns a `toot dict`_ with the new status. | ||
1859 | """ | ||
1860 | if quote_id is not None: | 1799 | if quote_id is not None: |
1861 | if self.feature_set != "fedibird": | 1800 | if self.feature_set != "fedibird": |
1862 | raise MastodonIllegalArgumentError( | 1801 | raise MastodonIllegalArgumentError('quote_id is only available with feature set fedibird') |
1863 | 'quote_id is only available with feature set fedibird') | ||
1864 | quote_id = self.__unpack_id(quote_id) | 1802 | quote_id = self.__unpack_id(quote_id) |
1865 | 1803 | ||
1866 | if content_type is not None: | 1804 | if content_type is not None: |
1867 | if self.feature_set != "pleroma": | 1805 | if self.feature_set != "pleroma": |
1868 | raise MastodonIllegalArgumentError( | 1806 | raise MastodonIllegalArgumentError('content_type is only available with feature set pleroma') |
1869 | 'content_type is only available with feature set pleroma') | ||
1870 | # It would be better to read this from nodeinfo and cache, but this is easier | 1807 | # It would be better to read this from nodeinfo and cache, but this is easier |
1871 | if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: | 1808 | if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: |
1872 | raise MastodonIllegalArgumentError( | 1809 | raise MastodonIllegalArgumentError('Invalid content type specified') |
1873 | 'Invalid content type specified') | ||
1874 | 1810 | ||
1875 | if in_reply_to_id is not None: | 1811 | if in_reply_to_id is not None: |
1876 | in_reply_to_id = self.__unpack_id(in_reply_to_id) | 1812 | in_reply_to_id = self.__unpack_id(in_reply_to_id) |
@@ -1893,8 +1829,7 @@ class Mastodon: | |||
1893 | else: | 1829 | else: |
1894 | params_initial['visibility'] = params_initial['visibility'].lower() | 1830 | params_initial['visibility'] = params_initial['visibility'].lower() |
1895 | if params_initial['visibility'] not in valid_visibilities: | 1831 | if params_initial['visibility'] not in valid_visibilities: |
1896 | raise ValueError('Invalid visibility value! Acceptable ' | 1832 | raise ValueError('Invalid visibility value! Acceptable values are %s' % valid_visibilities) |
1897 | 'values are %s' % valid_visibilities) | ||
1898 | 1833 | ||
1899 | if params_initial['language'] is None: | 1834 | if params_initial['language'] is None: |
1900 | del params_initial['language'] | 1835 | del params_initial['language'] |
@@ -1914,8 +1849,7 @@ class Mastodon: | |||
1914 | for media_id in media_ids: | 1849 | for media_id in media_ids: |
1915 | media_ids_proper.append(self.__unpack_id(media_id)) | 1850 | media_ids_proper.append(self.__unpack_id(media_id)) |
1916 | except Exception as e: | 1851 | except Exception as e: |
1917 | raise MastodonIllegalArgumentError("Invalid media " | 1852 | raise MastodonIllegalArgumentError("Invalid media dict: %s" % e) |
1918 | "dict: %s" % e) | ||
1919 | 1853 | ||
1920 | params_initial["media_ids"] = media_ids_proper | 1854 | params_initial["media_ids"] = media_ids_proper |
1921 | 1855 | ||
@@ -1926,8 +1860,89 @@ class Mastodon: | |||
1926 | if poll is not None: | 1860 | if poll is not None: |
1927 | use_json = True | 1861 | use_json = True |
1928 | 1862 | ||
1929 | params = self.__generate_params(params_initial, ['idempotency_key']) | 1863 | params = self.__generate_params(params_initial, ['idempotency_key', 'edit']) |
1930 | return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) | 1864 | if edit is None: |
1865 | # Post | ||
1866 | return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) | ||
1867 | else: | ||
1868 | # Edit | ||
1869 | return self.__api_request('PUT', '/api/v1/statuses/{0}'.format(str(self.__unpack_id(edit))), params, headers=headers, use_json=use_json) | ||
1870 | |||
1871 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | ||
1872 | def status_post(self, status, in_reply_to_id=None, media_ids=None, | ||
1873 | sensitive=False, visibility=None, spoiler_text=None, | ||
1874 | language=None, idempotency_key=None, content_type=None, | ||
1875 | scheduled_at=None, poll=None, quote_id=None): | ||
1876 | """ | ||
1877 | Post a status. Can optionally be in reply to another status and contain | ||
1878 | media. | ||
1879 | |||
1880 | `media_ids` should be a list. (If it's not, the function will turn it | ||
1881 | into one.) It can contain up to four pieces of media (uploaded via | ||
1882 | `media_post()`_). `media_ids` can also be the `media dicts`_ returned | ||
1883 | by `media_post()`_ - they are unpacked automatically. | ||
1884 | |||
1885 | The `sensitive` boolean decides whether or not media attached to the post | ||
1886 | should be marked as sensitive, which hides it by default on the Mastodon | ||
1887 | web front-end. | ||
1888 | |||
1889 | The visibility parameter is a string value and accepts any of: | ||
1890 | 'direct' - post will be visible only to mentioned users | ||
1891 | 'private' - post will be visible only to followers | ||
1892 | 'unlisted' - post will be public but not appear on the public timeline | ||
1893 | 'public' - post will be public | ||
1894 | |||
1895 | If not passed in, visibility defaults to match the current account's | ||
1896 | default-privacy setting (starting with Mastodon version 1.6) or its | ||
1897 | locked setting - private if the account is locked, public otherwise | ||
1898 | (for Mastodon versions lower than 1.6). | ||
1899 | |||
1900 | The `spoiler_text` parameter is a string to be shown as a warning before | ||
1901 | the text of the status. If no text is passed in, no warning will be | ||
1902 | displayed. | ||
1903 | |||
1904 | Specify `language` to override automatic language detection. The parameter | ||
1905 | accepts all valid ISO 639-2 language codes. | ||
1906 | |||
1907 | You can set `idempotency_key` to a value to uniquely identify an attempt | ||
1908 | at posting a status. Even if you call this function more than once, | ||
1909 | if you call it with the same `idempotency_key`, only one status will | ||
1910 | be created. | ||
1911 | |||
1912 | Pass a datetime as `scheduled_at` to schedule the toot for a specific time | ||
1913 | (the time must be at least 5 minutes into the future). If this is passed, | ||
1914 | status_post returns a `scheduled toot dict`_ instead. | ||
1915 | |||
1916 | Pass `poll` to attach a poll to the status. An appropriate object can be | ||
1917 | constructed using `make_poll()`_ . Note that as of Mastodon version | ||
1918 | 2.8.2, you can only have either media or a poll attached, not both at | ||
1919 | the same time. | ||
1920 | |||
1921 | **Specific to "pleroma" feature set:**: Specify `content_type` to set | ||
1922 | the content type of your post on Pleroma. It accepts 'text/plain' (default), | ||
1923 | 'text/markdown', 'text/html' and 'text/bbcode'. This parameter is not | ||
1924 | supported on Mastodon servers, but will be safely ignored if set. | ||
1925 | |||
1926 | **Specific to "fedibird" feature set:**: The `quote_id` parameter is | ||
1927 | a non-standard extension that specifies the id of a quoted status. | ||
1928 | |||
1929 | Returns a `toot dict`_ with the new status. | ||
1930 | """ | ||
1931 | return self.__status_internal( | ||
1932 | status, | ||
1933 | in_reply_to_id, | ||
1934 | media_ids, | ||
1935 | sensitive, | ||
1936 | visibility, | ||
1937 | spoiler_text, | ||
1938 | language, | ||
1939 | idempotency_key, | ||
1940 | content_type, | ||
1941 | scheduled_at, | ||
1942 | poll, | ||
1943 | quote_id, | ||
1944 | edit=None | ||
1945 | ) | ||
1931 | 1946 | ||
1932 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 1947 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) |
1933 | def toot(self, status): | 1948 | def toot(self, status): |
@@ -1940,6 +1955,45 @@ class Mastodon: | |||
1940 | """ | 1955 | """ |
1941 | return self.status_post(status) | 1956 | return self.status_post(status) |
1942 | 1957 | ||
1958 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS) | ||
1959 | def status_update(self, id, status = None, spoiler_text = None, sensitive = None, media_ids = None, poll = None): | ||
1960 | """ | ||
1961 | Edit a status. The meanings of the fields are largely the same as in `status_post()`_, | ||
1962 | though not every field can be edited. | ||
1963 | |||
1964 | Note that editing a poll will reset the votes. | ||
1965 | """ | ||
1966 | return self.__status_internal( | ||
1967 | status = status, | ||
1968 | media_ids = media_ids, | ||
1969 | sensitive = sensitive, | ||
1970 | spoiler_text = spoiler_text, | ||
1971 | poll = poll, | ||
1972 | edit = id | ||
1973 | ) | ||
1974 | |||
1975 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS_EDIT) | ||
1976 | def status_history(self, id): | ||
1977 | """ | ||
1978 | Returns the edit history of a status as a list of `status edit dicts`_, starting | ||
1979 | from the original form. Note that this means that a status that has been edited | ||
1980 | once will have *two* entries in this list, a status that has been edited twice | ||
1981 | will have three, and so on. | ||
1982 | """ | ||
1983 | id = self.__unpack_id(id) | ||
1984 | return self.__api_request('GET', "/api/v1/statuses/{0}/history".format(str(id))) | ||
1985 | |||
1986 | def status_source(self, id): | ||
1987 | """ | ||
1988 | Returns the source of a status for editing. | ||
1989 | |||
1990 | Return value is a dictionary containing exactly the parameters you could pass to | ||
1991 | `status_update()`_ to change nothing about the status, except `status` is `text` | ||
1992 | instead. | ||
1993 | """ | ||
1994 | id = self.__unpack_id(id) | ||
1995 | return self.__api_request('GET', "/api/v1/statuses/{0}/source".format(str(id))) | ||
1996 | |||
1943 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 1997 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) |
1944 | def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, | 1998 | def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, |
1945 | sensitive=False, visibility=None, spoiler_text=None, | 1999 | sensitive=False, visibility=None, spoiler_text=None, |
diff --git a/tests/cassettes/test_status_edit.yaml b/tests/cassettes/test_status_edit.yaml new file mode 100644 index 0000000..1343b28 --- /dev/null +++ b/tests/cassettes/test_status_edit.yaml | |||
@@ -0,0 +1,379 @@ | |||
1 | interactions: | ||
2 | - request: | ||
3 | body: status=the+best+editor%3F+why%2C+of+course+it+is+VS+Code | ||
4 | headers: | ||
5 | Accept: | ||
6 | - '*/*' | ||
7 | Accept-Encoding: | ||
8 | - gzip, deflate | ||
9 | Authorization: | ||
10 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN | ||
11 | Connection: | ||
12 | - keep-alive | ||
13 | Content-Length: | ||
14 | - '56' | ||
15 | Content-Type: | ||
16 | - application/x-www-form-urlencoded | ||
17 | User-Agent: | ||
18 | - tests/v311 | ||
19 | method: POST | ||
20 | uri: http://localhost:3000/api/v1/statuses | ||
21 | response: | ||
22 | body: | ||
23 | string: '{"id":"109384054168698393","created_at":"2022-11-21T22:03:29.362Z","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/109384054168698393","url":"http://localhost:3000/@mastodonpy_test/109384054168698393","replies_count":0,"reblogs_count":0,"favourites_count":0,"edited_at":null,"favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"content":"\u003cp\u003ethe | ||
24 | best editor? why, of course it is VS Code\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py | ||
25 | test suite","website":null},"account":{"id":"109383687546708201","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"group":false,"created_at":"2022-11-21T00:00:00.000Z","note":"","url":"http://localhost:3000/@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":6,"last_status_at":"2022-11-21","noindex":false,"emojis":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}' | ||
26 | headers: | ||
27 | Cache-Control: | ||
28 | - no-store | ||
29 | Content-Security-Policy: | ||
30 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
31 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
32 | style-src ''self'' http://localhost:3000 ''nonce-3UDW6mpgnOTfx5Euaa1LQA==''; | ||
33 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
34 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
35 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
36 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
37 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
38 | worker-src ''self'' blob: http://localhost:3000' | ||
39 | Content-Type: | ||
40 | - application/json; charset=utf-8 | ||
41 | ETag: | ||
42 | - W/"8a45eb762bdb11cdd6cd63bfebe39f63" | ||
43 | Referrer-Policy: | ||
44 | - strict-origin-when-cross-origin | ||
45 | Transfer-Encoding: | ||
46 | - chunked | ||
47 | Vary: | ||
48 | - Accept, Origin | ||
49 | X-Content-Type-Options: | ||
50 | - nosniff | ||
51 | X-Download-Options: | ||
52 | - noopen | ||
53 | X-Frame-Options: | ||
54 | - SAMEORIGIN | ||
55 | X-Permitted-Cross-Domain-Policies: | ||
56 | - none | ||
57 | X-RateLimit-Limit: | ||
58 | - '300' | ||
59 | X-RateLimit-Remaining: | ||
60 | - '292' | ||
61 | X-RateLimit-Reset: | ||
62 | - '2022-11-22T00:00:00.383365Z' | ||
63 | X-Request-Id: | ||
64 | - e56f662b-28f8-4ba7-9b38-36e71ac7d73c | ||
65 | X-Runtime: | ||
66 | - '0.033929' | ||
67 | X-XSS-Protection: | ||
68 | - 1; mode=block | ||
69 | status: | ||
70 | code: 200 | ||
71 | message: OK | ||
72 | - request: | ||
73 | body: null | ||
74 | headers: | ||
75 | Accept: | ||
76 | - '*/*' | ||
77 | Accept-Encoding: | ||
78 | - gzip, deflate | ||
79 | Authorization: | ||
80 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2 | ||
81 | Connection: | ||
82 | - keep-alive | ||
83 | User-Agent: | ||
84 | - tests/v311 | ||
85 | method: GET | ||
86 | uri: http://localhost:3000/api/v1/statuses/109384054168698393/history | ||
87 | response: | ||
88 | body: | ||
89 | string: '[]' | ||
90 | headers: | ||
91 | Cache-Control: | ||
92 | - no-store | ||
93 | Content-Security-Policy: | ||
94 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
95 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
96 | style-src ''self'' http://localhost:3000 ''nonce-oKku/pMs24FqYkpW5MkiGQ==''; | ||
97 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
98 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
99 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
100 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
101 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
102 | worker-src ''self'' blob: http://localhost:3000' | ||
103 | Content-Type: | ||
104 | - application/json; charset=utf-8 | ||
105 | ETag: | ||
106 | - W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" | ||
107 | Referrer-Policy: | ||
108 | - strict-origin-when-cross-origin | ||
109 | Transfer-Encoding: | ||
110 | - chunked | ||
111 | Vary: | ||
112 | - Accept, Origin | ||
113 | X-Content-Type-Options: | ||
114 | - nosniff | ||
115 | X-Download-Options: | ||
116 | - noopen | ||
117 | X-Frame-Options: | ||
118 | - SAMEORIGIN | ||
119 | X-Permitted-Cross-Domain-Policies: | ||
120 | - none | ||
121 | X-Request-Id: | ||
122 | - 4a780264-f947-4745-a5de-7165d8eee3d9 | ||
123 | X-Runtime: | ||
124 | - '0.010494' | ||
125 | X-XSS-Protection: | ||
126 | - 1; mode=block | ||
127 | status: | ||
128 | code: 200 | ||
129 | message: OK | ||
130 | - request: | ||
131 | body: status=the+best+editor%3F+why%2C+of+course+it+is+the+KDE+Advanced+Text+Editor%2C+Kate | ||
132 | headers: | ||
133 | Accept: | ||
134 | - '*/*' | ||
135 | Accept-Encoding: | ||
136 | - gzip, deflate | ||
137 | Authorization: | ||
138 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN | ||
139 | Connection: | ||
140 | - keep-alive | ||
141 | Content-Length: | ||
142 | - '85' | ||
143 | Content-Type: | ||
144 | - application/x-www-form-urlencoded | ||
145 | User-Agent: | ||
146 | - tests/v311 | ||
147 | method: PUT | ||
148 | uri: http://localhost:3000/api/v1/statuses/109384054168698393 | ||
149 | response: | ||
150 | body: | ||
151 | string: '{"id":"109384054168698393","created_at":"2022-11-21T22:03:29.362Z","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/109384054168698393","url":"http://localhost:3000/@mastodonpy_test/109384054168698393","replies_count":0,"reblogs_count":0,"favourites_count":0,"edited_at":"2022-11-21T22:03:29.418Z","favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"pinned":false,"content":"\u003cp\u003ethe | ||
152 | best editor? why, of course it is the KDE Advanced Text Editor, Kate\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py | ||
153 | test suite","website":null},"account":{"id":"109383687546708201","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"group":false,"created_at":"2022-11-21T00:00:00.000Z","note":"","url":"http://localhost:3000/@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":6,"last_status_at":"2022-11-21","noindex":false,"emojis":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}' | ||
154 | headers: | ||
155 | Cache-Control: | ||
156 | - no-store | ||
157 | Content-Security-Policy: | ||
158 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
159 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
160 | style-src ''self'' http://localhost:3000 ''nonce-11jMbHJPLcAv+qMX8EK9Eg==''; | ||
161 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
162 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
163 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
164 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
165 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
166 | worker-src ''self'' blob: http://localhost:3000' | ||
167 | Content-Type: | ||
168 | - application/json; charset=utf-8 | ||
169 | ETag: | ||
170 | - W/"976b69a807cf9d4601d0c73c8eb249fc" | ||
171 | Referrer-Policy: | ||
172 | - strict-origin-when-cross-origin | ||
173 | Transfer-Encoding: | ||
174 | - chunked | ||
175 | Vary: | ||
176 | - Accept, Origin | ||
177 | X-Content-Type-Options: | ||
178 | - nosniff | ||
179 | X-Download-Options: | ||
180 | - noopen | ||
181 | X-Frame-Options: | ||
182 | - SAMEORIGIN | ||
183 | X-Permitted-Cross-Domain-Policies: | ||
184 | - none | ||
185 | X-RateLimit-Limit: | ||
186 | - '300' | ||
187 | X-RateLimit-Remaining: | ||
188 | - '291' | ||
189 | X-RateLimit-Reset: | ||
190 | - '2022-11-22T00:00:00.437259Z' | ||
191 | X-Request-Id: | ||
192 | - 1f4c3ffd-1c13-45ee-a9df-8d7fff11a17c | ||
193 | X-Runtime: | ||
194 | - '0.033812' | ||
195 | X-XSS-Protection: | ||
196 | - 1; mode=block | ||
197 | status: | ||
198 | code: 200 | ||
199 | message: OK | ||
200 | - request: | ||
201 | body: null | ||
202 | headers: | ||
203 | Accept: | ||
204 | - '*/*' | ||
205 | Accept-Encoding: | ||
206 | - gzip, deflate | ||
207 | Authorization: | ||
208 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2 | ||
209 | Connection: | ||
210 | - keep-alive | ||
211 | User-Agent: | ||
212 | - tests/v311 | ||
213 | method: GET | ||
214 | uri: http://localhost:3000/api/v1/statuses/109384054168698393 | ||
215 | response: | ||
216 | body: | ||
217 | string: '{"id":"109384054168698393","created_at":"2022-11-21T22:03:29.362Z","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/109384054168698393","url":"http://localhost:3000/@mastodonpy_test/109384054168698393","replies_count":0,"reblogs_count":0,"favourites_count":0,"edited_at":"2022-11-21T22:03:29.418Z","favourited":false,"reblogged":false,"muted":false,"bookmarked":false,"content":"\u003cp\u003ethe | ||
218 | best editor? why, of course it is the KDE Advanced Text Editor, Kate\u003c/p\u003e","filtered":[],"reblog":null,"application":{"name":"Mastodon.py | ||
219 | test suite","website":null},"account":{"id":"109383687546708201","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"group":false,"created_at":"2022-11-21T00:00:00.000Z","note":"","url":"http://localhost:3000/@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":6,"last_status_at":"2022-11-21","noindex":false,"emojis":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null}' | ||
220 | headers: | ||
221 | Cache-Control: | ||
222 | - no-store | ||
223 | Content-Security-Policy: | ||
224 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
225 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
226 | style-src ''self'' http://localhost:3000 ''nonce-/HjTa7cbsYkrasMByN5dRw==''; | ||
227 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
228 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
229 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
230 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
231 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
232 | worker-src ''self'' blob: http://localhost:3000' | ||
233 | Content-Type: | ||
234 | - application/json; charset=utf-8 | ||
235 | ETag: | ||
236 | - W/"8d8244c105ccd1fff42ddc2e75976f91" | ||
237 | Referrer-Policy: | ||
238 | - strict-origin-when-cross-origin | ||
239 | Transfer-Encoding: | ||
240 | - chunked | ||
241 | Vary: | ||
242 | - Accept, Origin | ||
243 | X-Content-Type-Options: | ||
244 | - nosniff | ||
245 | X-Download-Options: | ||
246 | - noopen | ||
247 | X-Frame-Options: | ||
248 | - SAMEORIGIN | ||
249 | X-Permitted-Cross-Domain-Policies: | ||
250 | - none | ||
251 | X-Request-Id: | ||
252 | - 36c0e7e0-064a-42f1-91e0-82c90ebc4456 | ||
253 | X-Runtime: | ||
254 | - '0.030588' | ||
255 | X-XSS-Protection: | ||
256 | - 1; mode=block | ||
257 | status: | ||
258 | code: 200 | ||
259 | message: OK | ||
260 | - request: | ||
261 | body: null | ||
262 | headers: | ||
263 | Accept: | ||
264 | - '*/*' | ||
265 | Accept-Encoding: | ||
266 | - gzip, deflate | ||
267 | Authorization: | ||
268 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2 | ||
269 | Connection: | ||
270 | - keep-alive | ||
271 | User-Agent: | ||
272 | - tests/v311 | ||
273 | method: GET | ||
274 | uri: http://localhost:3000/api/v1/statuses/109384054168698393/history | ||
275 | response: | ||
276 | body: | ||
277 | string: '[{"content":"\u003cp\u003ethe best editor? why, of course it is VS | ||
278 | Code\u003c/p\u003e","spoiler_text":"","sensitive":false,"created_at":"2022-11-21T22:03:29.362Z","account":{"id":"109383687546708201","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"group":false,"created_at":"2022-11-21T00:00:00.000Z","note":"","url":"http://localhost:3000/@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":6,"last_status_at":"2022-11-21","noindex":false,"emojis":[],"fields":[]},"media_attachments":[],"emojis":[]},{"content":"\u003cp\u003ethe | ||
279 | best editor? why, of course it is the KDE Advanced Text Editor, Kate\u003c/p\u003e","spoiler_text":"","sensitive":false,"created_at":"2022-11-21T22:03:29.418Z","account":{"id":"109383687546708201","username":"mastodonpy_test","acct":"mastodonpy_test","display_name":"","locked":true,"bot":false,"discoverable":null,"group":false,"created_at":"2022-11-21T00:00:00.000Z","note":"","url":"http://localhost:3000/@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":6,"last_status_at":"2022-11-21","noindex":false,"emojis":[],"fields":[]},"media_attachments":[],"emojis":[]}]' | ||
280 | headers: | ||
281 | Cache-Control: | ||
282 | - no-store | ||
283 | Content-Security-Policy: | ||
284 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
285 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
286 | style-src ''self'' http://localhost:3000 ''nonce-mn4VRGJCjg55CXsiLcW5tA==''; | ||
287 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
288 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
289 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
290 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
291 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
292 | worker-src ''self'' blob: http://localhost:3000' | ||
293 | Content-Type: | ||
294 | - application/json; charset=utf-8 | ||
295 | ETag: | ||
296 | - W/"e5185ce4a3ebf261210613a8bb85e77e" | ||
297 | Referrer-Policy: | ||
298 | - strict-origin-when-cross-origin | ||
299 | Transfer-Encoding: | ||
300 | - chunked | ||
301 | Vary: | ||
302 | - Accept, Origin | ||
303 | X-Content-Type-Options: | ||
304 | - nosniff | ||
305 | X-Download-Options: | ||
306 | - noopen | ||
307 | X-Frame-Options: | ||
308 | - SAMEORIGIN | ||
309 | X-Permitted-Cross-Domain-Policies: | ||
310 | - none | ||
311 | X-Request-Id: | ||
312 | - 17896b84-96a0-4ed4-b3a0-8fca353a3725 | ||
313 | X-Runtime: | ||
314 | - '0.016628' | ||
315 | X-XSS-Protection: | ||
316 | - 1; mode=block | ||
317 | status: | ||
318 | code: 200 | ||
319 | message: OK | ||
320 | - request: | ||
321 | body: null | ||
322 | headers: | ||
323 | Accept: | ||
324 | - '*/*' | ||
325 | Accept-Encoding: | ||
326 | - gzip, deflate | ||
327 | Authorization: | ||
328 | - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2 | ||
329 | Connection: | ||
330 | - keep-alive | ||
331 | User-Agent: | ||
332 | - tests/v311 | ||
333 | method: GET | ||
334 | uri: http://localhost:3000/api/v1/statuses/109384054168698393/source | ||
335 | response: | ||
336 | body: | ||
337 | string: '{"id":"109384054168698393","text":"the best editor? why, of course | ||
338 | it is the KDE Advanced Text Editor, Kate","spoiler_text":""}' | ||
339 | headers: | ||
340 | Cache-Control: | ||
341 | - no-store | ||
342 | Content-Security-Policy: | ||
343 | - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src | ||
344 | ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; | ||
345 | style-src ''self'' http://localhost:3000 ''nonce-1CVpCwMC0PSWzPM4QmGGoA==''; | ||
346 | media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' | ||
347 | https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' | ||
348 | data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 | ||
349 | ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' | ||
350 | ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; | ||
351 | worker-src ''self'' blob: http://localhost:3000' | ||
352 | Content-Type: | ||
353 | - application/json; charset=utf-8 | ||
354 | ETag: | ||
355 | - W/"41ed5fd640708627beb7f31b84cb65d3" | ||
356 | Referrer-Policy: | ||
357 | - strict-origin-when-cross-origin | ||
358 | Transfer-Encoding: | ||
359 | - chunked | ||
360 | Vary: | ||
361 | - Accept, Origin | ||
362 | X-Content-Type-Options: | ||
363 | - nosniff | ||
364 | X-Download-Options: | ||
365 | - noopen | ||
366 | X-Frame-Options: | ||
367 | - SAMEORIGIN | ||
368 | X-Permitted-Cross-Domain-Policies: | ||
369 | - none | ||
370 | X-Request-Id: | ||
371 | - b5919220-e51e-4496-80f5-5a17e908702f | ||
372 | X-Runtime: | ||
373 | - '0.016356' | ||
374 | X-XSS-Protection: | ||
375 | - 1; mode=block | ||
376 | status: | ||
377 | code: 200 | ||
378 | message: OK | ||
379 | version: 1 | ||
diff --git a/tests/test_status.py b/tests/test_status.py index 20e32f2..e747571 100644 --- a/tests/test_status.py +++ b/tests/test_status.py | |||
@@ -213,3 +213,19 @@ def test_scheduled_status_long_part2(api): | |||
213 | if text in status.content: | 213 | if text in status.content: |
214 | found_status = True | 214 | found_status = True |
215 | assert found_status | 215 | assert found_status |
216 | |||
217 | @pytest.mark.vcr() | ||
218 | def test_status_edit(api, api2): | ||
219 | status = api.status_post("the best editor? why, of course it is VS Code") | ||
220 | edit_list_1 = api2.status_history(status) | ||
221 | status_edited = api.status_update(status, "the best editor? why, of course it is the KDE Advanced Text Editor, Kate") | ||
222 | status_result = api2.status(status) | ||
223 | edit_list_2 = api2.status_history(status) | ||
224 | |||
225 | assert len(edit_list_1) == 0 | ||
226 | assert len(edit_list_2) == 2 | ||
227 | assert "the best editor? why, of course it is the KDE Advanced Text Editor, Kate" in status_result.content | ||
228 | |||
229 | source = api2.status_source(status) | ||
230 | assert source.text == "the best editor? why, of course it is the KDE Advanced Text Editor, Kate" | ||
231 | \ No newline at end of file | ||