kopia lustrzana https://github.com/snarfed/bridgy-fed
return parsed JSON from common.get_as2(); use it in activitypub
rodzic
527ca5585b
commit
e985516dc3
|
@ -14,13 +14,6 @@ import webapp2
|
||||||
import common
|
import common
|
||||||
from models import MagicKey
|
from models import MagicKey
|
||||||
|
|
||||||
|
|
||||||
# https://www.w3.org/TR/activitypub/#retrieving-objects
|
|
||||||
CONTENT_TYPE_AS2 = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
|
||||||
CONTENT_TYPE_AS = 'application/activity+json'
|
|
||||||
CONNEG_HEADER = {
|
|
||||||
'Accept': '%s; q=0.9, %s; q=0.8' % (CONTENT_TYPE_AS2, CONTENT_TYPE_AS),
|
|
||||||
}
|
|
||||||
SUPPORTED_TYPES = (
|
SUPPORTED_TYPES = (
|
||||||
'Announce',
|
'Announce',
|
||||||
'Article',
|
'Article',
|
||||||
|
@ -31,6 +24,7 @@ SUPPORTED_TYPES = (
|
||||||
'Video',
|
'Video',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ActorHandler(webapp2.RequestHandler):
|
class ActorHandler(webapp2.RequestHandler):
|
||||||
"""Serves /[DOMAIN], fetches its mf2, converts to AS Actor, and serves it."""
|
"""Serves /[DOMAIN], fetches its mf2, converts to AS Actor, and serves it."""
|
||||||
|
|
||||||
|
@ -56,7 +50,7 @@ representative h-card</a> on %s""" % resp.url)
|
||||||
logging.info('Returning: %s', json.dumps(obj, indent=2))
|
logging.info('Returning: %s', json.dumps(obj, indent=2))
|
||||||
|
|
||||||
self.response.headers.update({
|
self.response.headers.update({
|
||||||
'Content-Type': CONTENT_TYPE_AS2,
|
'Content-Type': common.CONTENT_TYPE_AS2,
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
})
|
})
|
||||||
self.response.write(json.dumps(obj, indent=2))
|
self.response.write(json.dumps(obj, indent=2))
|
||||||
|
@ -86,8 +80,7 @@ class InboxHandler(webapp2.RequestHandler):
|
||||||
if activity.get('type') in ('Like', 'Announce'):
|
if activity.get('type') in ('Like', 'Announce'):
|
||||||
actor = activity.get('actor')
|
actor = activity.get('actor')
|
||||||
if actor:
|
if actor:
|
||||||
activity['actor'] = common.requests_get(
|
activity['actor'] = common.get_as2(actor)
|
||||||
actor, parse_json=True, headers=CONNEG_HEADER)
|
|
||||||
|
|
||||||
# send webmentions to each target
|
# send webmentions to each target
|
||||||
as1 = as2.to_as1(activity)
|
as1 = as2.to_as1(activity)
|
||||||
|
|
|
@ -95,7 +95,7 @@ def get_as2(url):
|
||||||
url: string
|
url: string
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
requests.Response
|
dict, AS2 object parsed from JSON
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
requests.HTTPError, webob.exc.HTTPException
|
requests.HTTPError, webob.exc.HTTPException
|
||||||
|
@ -107,7 +107,7 @@ def get_as2(url):
|
||||||
|
|
||||||
resp = requests_get(url, headers=CONNEG_HEADERS_AS2_HTML)
|
resp = requests_get(url, headers=CONNEG_HEADERS_AS2_HTML)
|
||||||
if resp.headers.get('Content-Type') in (CONTENT_TYPE_AS2, CONTENT_TYPE_AS2_LD):
|
if resp.headers.get('Content-Type') in (CONTENT_TYPE_AS2, CONTENT_TYPE_AS2_LD):
|
||||||
return resp
|
return resp.json()
|
||||||
|
|
||||||
parsed = BeautifulSoup(resp.content, from_encoding=resp.encoding)
|
parsed = BeautifulSoup(resp.content, from_encoding=resp.encoding)
|
||||||
as2 = parsed.find('link', rel=('alternate', 'self'), type=(
|
as2 = parsed.find('link', rel=('alternate', 'self'), type=(
|
||||||
|
@ -118,7 +118,7 @@ def get_as2(url):
|
||||||
resp = requests_get(urlparse.urljoin(resp.url, as2['href']),
|
resp = requests_get(urlparse.urljoin(resp.url, as2['href']),
|
||||||
headers=CONNEG_HEADERS_AS2)
|
headers=CONNEG_HEADERS_AS2)
|
||||||
if resp.headers.get('Content-Type') in (CONTENT_TYPE_AS2, CONTENT_TYPE_AS2_LD):
|
if resp.headers.get('Content-Type') in (CONTENT_TYPE_AS2, CONTENT_TYPE_AS2_LD):
|
||||||
return resp
|
return resp.json()
|
||||||
|
|
||||||
_error()
|
_error()
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ActivityPubTest(testutil.TestCase):
|
||||||
mock_get.assert_called_once_with('http://foo.com/', headers=common.HEADERS,
|
mock_get.assert_called_once_with('http://foo.com/', headers=common.HEADERS,
|
||||||
timeout=util.HTTP_TIMEOUT)
|
timeout=util.HTTP_TIMEOUT)
|
||||||
self.assertEquals(200, got.status_int)
|
self.assertEquals(200, got.status_int)
|
||||||
self.assertEquals(activitypub.CONTENT_TYPE_AS2, got.headers['Content-Type'])
|
self.assertEquals(common.CONTENT_TYPE_AS2, got.headers['Content-Type'])
|
||||||
self.assertEquals({
|
self.assertEquals({
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
'type' : 'Person',
|
'type' : 'Person',
|
||||||
|
@ -111,7 +111,7 @@ class ActivityPubTest(testutil.TestCase):
|
||||||
}
|
}
|
||||||
mock_get.side_effect = [
|
mock_get.side_effect = [
|
||||||
# source actor
|
# source actor
|
||||||
requests_response(actor),
|
requests_response(actor, headers={'Content-Type': common.CONTENT_TYPE_AS2}),
|
||||||
# target post webmention discovery
|
# target post webmention discovery
|
||||||
requests_response(
|
requests_response(
|
||||||
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
||||||
|
@ -134,7 +134,7 @@ class ActivityPubTest(testutil.TestCase):
|
||||||
self.assertEquals(200, got.status_int)
|
self.assertEquals(200, got.status_int)
|
||||||
|
|
||||||
as2_headers = copy.deepcopy(common.HEADERS)
|
as2_headers = copy.deepcopy(common.HEADERS)
|
||||||
as2_headers.update(activitypub.CONNEG_HEADER)
|
as2_headers.update(common.CONNEG_HEADERS_AS2_HTML)
|
||||||
mock_get.assert_has_calls((
|
mock_get.assert_has_calls((
|
||||||
call('http://orig/actor', headers=as2_headers, timeout=15),
|
call('http://orig/actor', headers=as2_headers, timeout=15),
|
||||||
call('http://orig/post', headers=common.HEADERS, verify=False),
|
call('http://orig/post', headers=common.HEADERS, verify=False),
|
||||||
|
|
|
@ -23,7 +23,8 @@ HTML_WITH_AS2 = requests_response("""\
|
||||||
""", headers={
|
""", headers={
|
||||||
'Content-Type': common.CONTENT_TYPE_HTML,
|
'Content-Type': common.CONTENT_TYPE_HTML,
|
||||||
})
|
})
|
||||||
AS2 = requests_response({}, headers={
|
AS2_OBJ = {'foo': ['bar']}
|
||||||
|
AS2 = requests_response(AS2_OBJ, headers={
|
||||||
'Content-Type': common.CONTENT_TYPE_AS2,
|
'Content-Type': common.CONTENT_TYPE_AS2,
|
||||||
})
|
})
|
||||||
NOT_ACCEPTABLE = requests_response(status=406)
|
NOT_ACCEPTABLE = requests_response(status=406)
|
||||||
|
@ -34,7 +35,7 @@ class CommonTest(testutil.TestCase):
|
||||||
@mock.patch('requests.get', return_value=AS2)
|
@mock.patch('requests.get', return_value=AS2)
|
||||||
def test_get_as2_direct(self, mock_get):
|
def test_get_as2_direct(self, mock_get):
|
||||||
resp = common.get_as2('http://orig')
|
resp = common.get_as2('http://orig')
|
||||||
self.assertEqual(AS2, resp)
|
self.assertEqual(AS2_OBJ, resp)
|
||||||
mock_get.assert_has_calls((
|
mock_get.assert_has_calls((
|
||||||
self.req('http://orig', headers=common.CONNEG_HEADERS_AS2_HTML),
|
self.req('http://orig', headers=common.CONNEG_HEADERS_AS2_HTML),
|
||||||
))
|
))
|
||||||
|
@ -42,7 +43,7 @@ class CommonTest(testutil.TestCase):
|
||||||
@mock.patch('requests.get', side_effect=[HTML_WITH_AS2, AS2])
|
@mock.patch('requests.get', side_effect=[HTML_WITH_AS2, AS2])
|
||||||
def test_get_as2_via_html(self, mock_get):
|
def test_get_as2_via_html(self, mock_get):
|
||||||
resp = common.get_as2('http://orig')
|
resp = common.get_as2('http://orig')
|
||||||
self.assertEqual(AS2, resp)
|
self.assertEqual(AS2_OBJ, resp)
|
||||||
mock_get.assert_has_calls((
|
mock_get.assert_has_calls((
|
||||||
self.req('http://orig', headers=common.CONNEG_HEADERS_AS2_HTML),
|
self.req('http://orig', headers=common.CONNEG_HEADERS_AS2_HTML),
|
||||||
self.req('http://as2', headers=common.CONNEG_HEADERS_AS2),
|
self.req('http://as2', headers=common.CONNEG_HEADERS_AS2),
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
"""Common test utility code.
|
"""Common test utility code.
|
||||||
"""
|
"""
|
||||||
|
import copy
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from google.appengine.datastore import datastore_stub_util
|
from google.appengine.datastore import datastore_stub_util
|
||||||
from google.appengine.ext import testbed
|
from google.appengine.ext import testbed
|
||||||
|
from mock import call
|
||||||
|
from oauth_dropins.webutil import testutil, util
|
||||||
|
|
||||||
from oauth_dropins.webutil import testutil
|
import common
|
||||||
|
|
||||||
|
|
||||||
class TestCase(unittest.TestCase, testutil.Asserts):
|
class TestCase(unittest.TestCase, testutil.Asserts):
|
||||||
|
@ -24,3 +27,11 @@ class TestCase(unittest.TestCase, testutil.Asserts):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.testbed.deactivate()
|
self.testbed.deactivate()
|
||||||
super(TestCase, self).tearDown()
|
super(TestCase, self).tearDown()
|
||||||
|
|
||||||
|
def req(self, url, **kwargs):
|
||||||
|
"""Returns a mock requests call."""
|
||||||
|
headers = copy.deepcopy(common.HEADERS)
|
||||||
|
headers.update(kwargs.get('headers', {}))
|
||||||
|
kwargs['headers'] = headers
|
||||||
|
kwargs.setdefault('timeout', util.HTTP_TIMEOUT)
|
||||||
|
return call(url, **kwargs)
|
||||||
|
|
Ładowanie…
Reference in New Issue