Add support for new Diaspora timestamp format

Diaspora protocol changed to ISO 8601 timestamp format in protocol version 0.1.6.

Closes #67
merge-requests/130/head
Jason Robinson 2017-01-28 10:58:14 +02:00
rodzic 2a10cb9ffd
commit f6a5438a54
7 zmienionych plików z 48 dodań i 11 usunięć

Wyświetl plik

@ -2,6 +2,9 @@
## [unreleased] ## [unreleased]
### Added
* Add support for new Diaspora protocol ISO 8601 timestamp format introduced in protocol version 0.1.6.
### Fixes ### Fixes
* Don't crash `federation.utils.diaspora.retrieve_diaspora_webfinger` if XRD parse raises an `xml.parsers.expat.ExpatError`. * Don't crash `federation.utils.diaspora.retrieve_diaspora_webfinger` if XRD parse raises an `xml.parsers.expat.ExpatError`.

Wyświetl plik

@ -15,3 +15,6 @@ pytest-warnings
sphinx sphinx
sphinx-autobuild sphinx-autobuild
recommonmark recommonmark
# Some datetime magic
arrow

Wyświetl plik

@ -141,7 +141,12 @@ def transform_attributes(attrs):
elif key in BOOLEAN_KEYS: elif key in BOOLEAN_KEYS:
transformed[key] = True if value == "true" else False transformed[key] = True if value == "true" else False
elif key in DATETIME_KEYS: elif key in DATETIME_KEYS:
transformed[key] = datetime.strptime(value, "%Y-%m-%d %H:%M:%S %Z") try:
# New style timestamps since in protocol 0.1.6
transformed[key] = datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
except ValueError:
# Legacy style timestamps
transformed[key] = datetime.strptime(value, "%Y-%m-%d %H:%M:%S %Z")
elif key in INTEGER_KEYS: elif key in INTEGER_KEYS:
transformed[key] = int(value) transformed[key] = int(value)
else: else:

Wyświetl plik

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import inspect import inspect
from dateutil.tz import tzlocal, tzutc from dateutil.tz import tzlocal, tzutc
@ -21,7 +20,7 @@ def format_dt(dt):
Format a datetime in the way that D* nodes expect. Format a datetime in the way that D* nodes expect.
""" """
return ensure_timezone(dt).astimezone(tzutc()).strftime( return ensure_timezone(dt).astimezone(tzutc()).strftime(
'%Y-%m-%d %H:%M:%S %Z' '%Y-%m-%dT%H:%M:%SZ'
) )

Wyświetl plik

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from datetime import datetime from datetime import datetime
from unittest.mock import patch from unittest.mock import patch
@ -15,7 +14,7 @@ from federation.entities.diaspora.mappers import message_to_objects, get_outboun
from federation.tests.fixtures.payloads import ( from federation.tests.fixtures.payloads import (
DIASPORA_POST_SIMPLE, DIASPORA_POST_COMMENT, DIASPORA_POST_LIKE, DIASPORA_POST_SIMPLE, DIASPORA_POST_COMMENT, DIASPORA_POST_LIKE,
DIASPORA_REQUEST, DIASPORA_PROFILE, DIASPORA_POST_INVALID, DIASPORA_RETRACTION, DIASPORA_REQUEST, DIASPORA_PROFILE, DIASPORA_POST_INVALID, DIASPORA_RETRACTION,
DIASPORA_POST_WITH_PHOTOS) DIASPORA_POST_WITH_PHOTOS, DIASPORA_POST_LEGACY_TIMESTAMP)
def mock_fill(attributes): def mock_fill(attributes):
@ -37,6 +36,11 @@ class TestDiasporaEntityMappersReceive(object):
assert post.created_at == datetime(2011, 7, 20, 1, 36, 7) assert post.created_at == datetime(2011, 7, 20, 1, 36, 7)
assert post.provider_display_name == "Socialhome" assert post.provider_display_name == "Socialhome"
def test_message_to_objects_legact_timestamp(self):
entities = message_to_objects(DIASPORA_POST_LEGACY_TIMESTAMP)
post = entities[0]
assert post.created_at == datetime(2011, 7, 20, 1, 36, 7)
def test_message_to_objects_post_with_photos(self): def test_message_to_objects_post_with_photos(self):
entities = message_to_objects(DIASPORA_POST_WITH_PHOTOS) entities = message_to_objects(DIASPORA_POST_WITH_PHOTOS)
assert len(entities) == 1 assert len(entities) == 1

Wyświetl plik

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*- import datetime
import re import re
import arrow
from federation.entities.base import Post from federation.entities.base import Post
from federation.entities.diaspora.utils import get_base_attributes, get_full_xml_representation from federation.entities.diaspora.utils import get_base_attributes, get_full_xml_representation, format_dt
class TestGetBaseAttributes(object): class TestGetBaseAttributes(object):
@ -22,3 +24,9 @@ class TestGetFullXMLRepresentation(object):
assert document == "<XML><post><status_message><raw_message></raw_message><guid></guid>" \ assert document == "<XML><post><status_message><raw_message></raw_message><guid></guid>" \
"<diaspora_handle></diaspora_handle><public>false</public>" \ "<diaspora_handle></diaspora_handle><public>false</public>" \
"<provider_display_name></provider_display_name></status_message></post></XML>" "<provider_display_name></provider_display_name></status_message></post></XML>"
class TestFormatDt(object):
def test_formatted_string_returned_from_tz_aware_datetime(self):
dt = arrow.get(datetime.datetime(2017, 1, 28, 3, 2, 3), "Europe/Helsinki").datetime
assert format_dt(dt) == "2017-01-28T01:02:03Z"

Wyświetl plik

@ -29,6 +29,21 @@ UNENCRYPTED_DIASPORA_PAYLOAD = """<?xml version='1.0'?>
DIASPORA_POST_SIMPLE = """<XML> DIASPORA_POST_SIMPLE = """<XML>
<post>
<status_message>
<raw_message>((status message))</raw_message>
<guid>((guidguidguidguidguidguidguid))</guid>
<diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle>
<public>false</public>
<created_at>2011-07-20T01:36:07Z</created_at>
<provider_display_name>Socialhome</provider_display_name>
</status_message>
</post>
</XML>
"""
DIASPORA_POST_LEGACY_TIMESTAMP = """<XML>
<post> <post>
<status_message> <status_message>
<raw_message>((status message))</raw_message> <raw_message>((status message))</raw_message>
@ -50,13 +65,13 @@ DIASPORA_POST_WITH_PHOTOS = """<XML>
<guid>((guidguidguidguidguidguidguid))</guid> <guid>((guidguidguidguidguidguidguid))</guid>
<diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle> <diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle>
<public>false</public> <public>false</public>
<created_at>2011-07-20 01:36:07 UTC</created_at> <created_at>2011-07-20T01:36:07Z</created_at>
<provider_display_name>Socialhome</provider_display_name> <provider_display_name>Socialhome</provider_display_name>
<photo> <photo>
<guid>((guidguidguidguidguidguidguif))</guid> <guid>((guidguidguidguidguidguidguif))</guid>
<diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle> <diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle>
<public>false</public> <public>false</public>
<created_at>2011-07-20 01:36:07 UTC</created_at> <created_at>2011-07-20T01:36:07Z</created_at>
<remote_photo_path>https://alice.diaspora.example.org/uploads/images/</remote_photo_path> <remote_photo_path>https://alice.diaspora.example.org/uploads/images/</remote_photo_path>
<remote_photo_name>1234.jpg</remote_photo_name> <remote_photo_name>1234.jpg</remote_photo_name>
<text/> <text/>
@ -68,7 +83,7 @@ DIASPORA_POST_WITH_PHOTOS = """<XML>
<guid>((guidguidguidguidguidguidguig))</guid> <guid>((guidguidguidguidguidguidguig))</guid>
<diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle> <diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle>
<public>false</public> <public>false</public>
<created_at>2011-07-20 01:36:07 UTC</created_at> <created_at>2011-07-20T01:36:07Z</created_at>
<remote_photo_path>https://alice.diaspora.example.org/uploads/images/</remote_photo_path> <remote_photo_path>https://alice.diaspora.example.org/uploads/images/</remote_photo_path>
<remote_photo_name>12345.jpg</remote_photo_name> <remote_photo_name>12345.jpg</remote_photo_name>
<text>foobar</text> <text>foobar</text>
@ -88,7 +103,7 @@ DIASPORA_POST_INVALID = """<XML>
<raw_message>((status message))</raw_message> <raw_message>((status message))</raw_message>
<diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle> <diaspora_handle>alice@alice.diaspora.example.org</diaspora_handle>
<public>false</public> <public>false</public>
<created_at>2011-07-20 01:36:07 UTC</created_at> <created_at>2011-07-20T01:36:07Z</created_at>
<provider_display_name>Socialhome</provider_display_name> <provider_display_name>Socialhome</provider_display_name>
</status_message> </status_message>
</post> </post>