rename Protocol.serve => .convert, move Content-Type to class constant

pull/698/head
Ryan Barrett 2023-10-24 16:09:28 -07:00
rodzic c3c3c17c9d
commit acb1c703a3
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
10 zmienionych plików z 56 dodań i 39 usunięć

Wyświetl plik

@ -64,6 +64,7 @@ class ActivityPub(User, Protocol):
"""
ABBREV = 'ap'
LOGO_HTML = '<img src="/static/fediverse_logo.svg">'
CONTENT_TYPE = as2.CONTENT_TYPE
def _pre_put_hook(self):
"""Validate id, require URL, don't allow Bridgy Fed domains.
@ -317,10 +318,16 @@ class ActivityPub(User, Protocol):
return False
@classmethod
def serve(cls, obj):
"""Serves a :class:`models.Object` as AS2."""
return (postprocess_as2(as2.from_as1(obj.as1)),
{'Content-Type': as2.CONTENT_TYPE})
def convert(cls, obj):
"""Convert a :class:`models.Object` to AS2.
Args:
obj (models.Object)
Returns:
dict: AS2 JSON
"""
return postprocess_as2(as2.from_as1(obj.as1))
@classmethod
def verify_signature(cls, activity):

Wyświetl plik

@ -59,6 +59,7 @@ class ATProto(User, Protocol):
ABBREV = 'atproto'
LOGO_HTML = '<img src="/static/atproto_logo.png">'
PDS_URL = f'https://{ABBREV}{common.SUPERDOMAIN}/'
CONTENT_TYPE = 'application/json'
def _pre_put_hook(self):
"""Validate id, require did:plc or non-blocklisted did:web.
@ -374,16 +375,21 @@ class ATProto(User, Protocol):
return True
@classmethod
def serve(cls, obj):
"""Serves a :class:`models.Object` as AS2.
def convert(cls, obj):
"""Converts a :class:`models.Object` to ``app.bsky.*`` lexicon JSON.
This is minimally implemented to serve ``app.bsky.*`` lexicon data, but
BGSes and other clients will generally receive ATProto commits via
``com.atproto.sync.subscribeRepos`` subscriptions, not BF-specific
``/convert/...`` HTTP requests, so this should never be used in
practice.
This is implemented, but BGSes and other clients will generally receive
ATProto commits via ``com.atproto.sync.subscribeRepos`` subscriptions,
not BF-specific ``/convert/...`` HTTP requests, so in practice, this
should be used rarely, if ever.
Args:
obj (models.Object)
Returns:
dict: JSON object
"""
return bluesky.from_as1(obj.as1), {'Content-Type': 'application/json'}
return bluesky.from_as1(obj.as1)
# URL route is registered in hub.py

Wyświetl plik

@ -102,7 +102,7 @@ def convert(dest, _, src=None):
return '', 410
# convert and serve
return dest_cls.serve(obj)
return dest_cls.convert(obj), {'Content-Type': dest_cls.CONTENT_TYPE}
@app.get('/render')

Wyświetl plik

@ -61,10 +61,13 @@ class Protocol:
OTHER_LABELS (list of str): label aliases
ABBREV (str): lower case abbreviation, used in URL paths
LOGO_HTML (str): logo emoji or ``<img>`` tag
CONTENT_TYPE (str): MIME type of this protocol's native data format,
appropriate for the ``Content-Type`` HTTP header.
"""
ABBREV = None
OTHER_LABELS = ()
LOGO_HTML = ''
CONTENT_TYPE = None
def __init__(self):
assert False
@ -407,12 +410,11 @@ class Protocol:
raise NotImplementedError()
@classmethod
def serve(cls, obj):
"""Returns this protocol's Flask response for a given :class:`Object`.
def convert(cls, obj):
"""Converts an :class:`Object` to this protocol's data format.
For example, an HTML string and ``text/html`` for :class:`Web`,
or a dict with AS2 JSON and ``application/activity+json`` for
:class:`ActivityPub`.
For example, an HTML string for :class:`Web`, or a dict with AS2 JSON
and ``application/activity+json`` for :class:`ActivityPub`.
To be implemented by subclasses.
@ -420,8 +422,7 @@ class Protocol:
obj (models.Object):
Returns:
(str, dict): (response body, HTTP headers) tuple appropriate to be
returned from a Flask handler
converted object data
"""
raise NotImplementedError()

Wyświetl plik

@ -102,7 +102,7 @@ def redir(to):
return f'Object not found: {to}', 404
g.user = Web.get_or_create(util.domain_from_link(to), direct=False, obj=obj)
ret, _ = ActivityPub.serve(obj)
ret = ActivityPub.convert(obj)
logger.info(f'Returning: {json_dumps(ret, indent=2)}')
return ret, {
'Content-Type': accept_type,

Wyświetl plik

@ -1975,10 +1975,9 @@ class ActivityPubUtilsTest(TestCase):
self.assertIsNone(obj.as1)
@skip
def test_serve(self):
def test_convert(self):
obj = Object(id='http://orig', as2=LIKE)
self.assertEqual((LIKE_WRAPPED, {'Content-Type': 'application/activity+json'}),
ActivityPub.serve(obj))
self.assertEqual(LIKE_WRAPPED, ActivityPub.convert(obj))
def test_postprocess_as2_idempotent(self):
g.user = self.make_user('foo.com')

Wyświetl plik

@ -233,16 +233,14 @@ class ATProtoTest(TestCase):
},
)
def test_serve(self):
def test_convert(self):
obj = self.store_object(id='http://orig', our_as1=ACTOR_AS)
expected = trim_nulls({
**ACTOR_PROFILE_BSKY,
'avatar': None,
'banner': None,
})
self.assertEqual(
(expected, {'Content-Type': 'application/json'}),
ATProto.serve(obj))
self.assertEqual(expected, ATProto.convert(obj))
@patch('requests.get', return_value=requests_response('', status=404))
def test_web_url(self, mock_get):

Wyświetl plik

@ -2269,9 +2269,8 @@ class WebUtilTest(TestCase):
'target': 'https://user.com/post',
}, kwargs['data'])
def test_serve(self, _, __):
def test_convert(self, _, __):
obj = Object(id='http://orig', mf2=ACTOR_MF2)
html, headers = Web.serve(obj)
self.assert_multiline_equals("""\
<!DOCTYPE html>
<html>
@ -2284,8 +2283,7 @@ class WebUtilTest(TestCase):
</span>
</body>
</html>
""", html, ignore_blanks=True)
self.assertEqual({'Content-Type': 'text/html; charset=utf-8'}, headers)
""", Web.convert(obj), ignore_blanks=True)
def test_target_for(self, _, __):
self.assertIsNone(Web.target_for(Object(id='x', source_protocol='web')))

Wyświetl plik

@ -64,6 +64,7 @@ COMMENT = {
class Fake(User, protocol.Protocol):
ABBREV = 'fa'
CONTENT_TYPE = 'fa/ke'
# maps string ids to dict AS1 objects that can be fetched
fetchable = {}
@ -122,10 +123,9 @@ class Fake(User, protocol.Protocol):
return False
@classmethod
def serve(cls, obj):
logger.info(f'{cls.__name__}.load {obj.key.id()}')
return (f'{cls.__name__} object {obj.key.id()}',
{'Accept': 'fake/protocol'})
def convert(cls, obj):
logger.info(f'{cls.__name__}.convert {obj.key.id()}')
return obj.as1
@classmethod
def target_for(cls, obj, shared=False):

14
web.py
Wyświetl plik

@ -69,6 +69,7 @@ class Web(User, Protocol):
ABBREV = 'web'
OTHER_LABELS = ('webmention',)
LOGO_HTML = '🕸️'
CONTENT_TYPE = common.CONTENT_TYPE_HTML
has_redirects = ndb.BooleanProperty()
redirects_error = ndb.TextProperty()
@ -437,8 +438,15 @@ class Web(User, Protocol):
return True
@classmethod
def serve(cls, obj):
"""Serves an :class:`Object` as HTML."""
def convert(cls, obj):
"""Converts a :class:`Object` to HTML.
Args:
obj (models.Object)
Returns:
str:
"""
obj_as1 = obj.as1
from_proto = PROTOCOLS.get(obj.source_protocol)
@ -463,7 +471,7 @@ class Web(User, Protocol):
refresh = f'<meta http-equiv="refresh" content="0;url={url}">'
html = html.replace(utf8, utf8 + '\n' + refresh)
return html, {'Content-Type': common.CONTENT_TYPE_HTML}
return html
@app.get('/web-site')