From 897b3a23cf4177675f0769de68f08ad8c4faf335 Mon Sep 17 00:00:00 2001 From: halcy Date: Thu, 17 Nov 2022 23:25:41 +0200 Subject: add server datetime retriever, fix tests some more --- mastodon/Mastodon.py | 35 +++++++++++++------ tests/cassettes/test_server_time.yaml | 63 +++++++++++++++++++++++++++++++++++ tests/test_instance.py | 7 +++- tests/test_notifications.py | 1 + tests/test_status.py | 1 + 5 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 tests/cassettes/test_server_time.yaml diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 05ebaaa..44e3b52 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py @@ -481,8 +481,7 @@ class Mastodon: # instance() was added in 1.1.0, so our best guess is 1.0.0. version_str = "1.0.0" - self.mastodon_major, self.mastodon_minor, self.mastodon_patch = parse_version_string( - version_str) + self.mastodon_major, self.mastodon_minor, self.mastodon_patch = parse_version_string(version_str) return version_str def verify_minimum_version(self, version_str, cached=False): @@ -503,7 +502,24 @@ class Mastodon: elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch: return False return True + + def get_approx_server_time(self): + """ + Retrieve the approximate server time + + We parse this from the hopefully present "Date" header, but make no effort to compensate for latency. + """ + response = self.__api_request("HEAD", "/", return_response_object=True) + print(response.headers) + if 'Date' in response.headers: + server_time_datetime = dateutil.parser.parse(response.headers['Date']) + # Make sure we're in local time + epoch_time = self.__datetime_to_epoch(server_time_datetime) + return datetime.datetime.fromtimestamp(epoch_time) + else: + raise MastodonAPIError("No server time in response.") + @staticmethod def get_supported_version(): """ @@ -937,7 +953,7 @@ class Mastodon: Returns a `card dict`_. """ - if self.verify_minimum_version("3.0.0"): + if self.verify_minimum_version("3.0.0", cached=True): return self.status(id).card else: id = self.__unpack_id(id) @@ -2139,7 +2155,7 @@ class Mastodon: """ id = self.__unpack_id(id) - if self.verify_minimum_version("2.9.2"): + if self.verify_minimum_version("2.9.2", cached=True): url = '/api/v1/notifications/{0}/dismiss'.format(str(id)) self.__api_request('POST', url) else: @@ -2590,14 +2606,14 @@ class Mastodon: focus = str(focus[0]) + "," + str(focus[1]) if not thumbnail is None: - if not self.verify_minimum_version("3.2.0"): + if not self.verify_minimum_version("3.2.0", cached=True): raise MastodonVersionError( 'Thumbnail requires version > 3.2.0') files["thumbnail"] = self.__load_media_file( thumbnail, thumbnail_mime_type) # Disambiguate URL by version - if self.verify_minimum_version("3.1.4"): + if self.verify_minimum_version("3.1.4", cached=True): ret_dict = self.__api_request( 'POST', '/api/v2/media', files=files, params={'description': description, 'focus': focus}) else: @@ -2637,7 +2653,7 @@ class Mastodon: locals(), ['id', 'thumbnail', 'thumbnail_mime_type']) if not thumbnail is None: - if not self.verify_minimum_version("3.2.0"): + if not self.verify_minimum_version("3.2.0", cached=True): raise MastodonVersionError( 'Thumbnail requires version > 3.2.0') files = {"thumbnail": self.__load_media_file( @@ -3359,8 +3375,7 @@ class Mastodon: else: date_time_utc = date_time.astimezone(pytz.utc) - epoch_utc = datetime.datetime.utcfromtimestamp( - 0).replace(tzinfo=pytz.utc) + epoch_utc = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc) return (date_time_utc - epoch_utc).total_seconds() @@ -3632,7 +3647,7 @@ class Mastodon: response_object.status_code, response_object.reason, error_msg) - + if return_response_object: return response_object diff --git a/tests/cassettes/test_server_time.yaml b/tests/cassettes/test_server_time.yaml new file mode 100644 index 0000000..a94b3aa --- /dev/null +++ b/tests/cassettes/test_server_time.yaml @@ -0,0 +1,63 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer __MASTODON_PY_TEST_ACCESS_TOKEN + Connection: + - keep-alive + User-Agent: + - tests/v311 + method: HEAD + uri: http://localhost:3000/ + response: + body: + string: '' + headers: + Cache-Control: + - max-age=0, public + Content-Security-Policy: + - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src + ''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000; + style-src ''self'' http://localhost:3000 ''nonce-2+ENJYUdR8BJrDBHHtp0Iw==''; + media-src ''self'' https: data: http://localhost:3000; frame-src ''self'' + https:; manifest-src ''self'' http://localhost:3000; connect-src ''self'' + data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000 + ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline'' + ''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000; + worker-src ''self'' blob: http://localhost:3000' + Content-Type: + - text/html; charset=utf-8 + Date: + - Thu, 17 Nov 2022 20:42:32 GMT + ETag: + - W/"9bb3b62cb5fb0388ee3b972a95ee0633" + Referrer-Policy: + - origin + Set-Cookie: + - _mastodon_session=S%2F25BrjlEMmL38vg%2FCMcsvHcd8%2BW45HbUkMBwTiqvTgNnzQ%2FhKVYvwORXtqZ5IgNVXl7gMcJ7SxG9y1ks1LN%2Bw3rvgb%2FxECYIlBWY7C3m%2B0aWsWG%2F8iNJsZfHvXlEY3xQxDzenmA2Mw35wRyPiT%2FSUJvwM9I5RtY1iUDsaCPzUbhGFcw3aoGUTdeag37%2FfGsJuG%2F9JsR0jj%2FCgWAlokV8%2Freu8XPUBFFDmjV9SdyFfzsIvP8%2Bd7cAebpCpaqp2DPngNSm8k6xgqXCuMCqpNc09slWQHzfDVqtWPTCMc95SmGpO0DOethwA44F8WbsfX1x5HGml8%3D--x1Ipi2xI5V5ct712--m3eM1Vf8f4oi87fjm0LEvw%3D%3D; + path=/; HttpOnly; SameSite=Lax + Vary: + - Accept + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Request-Id: + - 9d6b0c84-dff7-481a-a975-c669b8469976 + X-Runtime: + - '0.691929' + X-XSS-Protection: + - 1; mode=block + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_instance.py b/tests/test_instance.py index 2762ecb..5de61f6 100644 --- a/tests/test_instance.py +++ b/tests/test_instance.py @@ -1,6 +1,7 @@ import pytest from mastodon.Mastodon import MastodonVersionError +import datetime @pytest.mark.vcr() def test_instance(api): @@ -36,7 +37,11 @@ def test_emoji(api): @pytest.mark.vcr() def test_health(api): assert api.instance_health() == True - + +@pytest.mark.vcr() +def test_server_time(api): + assert isinstance(api.get_approx_server_time(), datetime.datetime) + @pytest.mark.vcr() def test_nodeinfo(api): nodeinfo = api.instance_nodeinfo() diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 0be81c6..6e761ce 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -26,6 +26,7 @@ def test_notifications_dismiss_pre_2_9_2(api, api2): try: status = api2.status_post('@mastodonpy_test hello!') notifications = api.notifications() + api.verify_minimum_version("2.9.2", cached=False) api.notifications_dismiss(notifications[0]) finally: if not status is None: diff --git a/tests/test_status.py b/tests/test_status.py index 7e30362..f45634f 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -53,6 +53,7 @@ def test_status_card_pre_2_9_2(api): import time status = api.status_post("http://example.org/") time.sleep(5) # Card generation may take time + api.verify_minimum_version("2.9.2", cached=False) card = api.status_card(status['id']) try: assert card -- cgit v1.2.3