kopia lustrzana https://github.com/snarfed/bridgy-fed
				
				
				
			activitypub actor endpoint: fetch mf2, convert to AS
							rodzic
							
								
									3928147414
								
							
						
					
					
						commit
						60a3f7b1cb
					
				|  | @ -0,0 +1,51 @@ | |||
| # coding=utf-8 | ||||
| """Handles requests for ActivityPub endpoints: actors, inbox, etc. | ||||
| """ | ||||
| import json | ||||
| import logging | ||||
| 
 | ||||
| import appengine_config | ||||
| 
 | ||||
| from granary import microformats2 | ||||
| import mf2py | ||||
| import mf2util | ||||
| import requests | ||||
| import webapp2 | ||||
| 
 | ||||
| 
 | ||||
| # https://www.w3.org/TR/activitypub/#retrieving-objects | ||||
| CONTENT_TYPE = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' | ||||
| USER_AGENT = 'bridgy-activitypub (https://activitypub.brid.gy/)' | ||||
| 
 | ||||
| 
 | ||||
| class ActorHandler(webapp2.RequestHandler): | ||||
|     """Serves /[DOMAIN], fetches its mf2, converts to AS Actor, and serves it.""" | ||||
| 
 | ||||
|     def get(self, domain): | ||||
|         url = 'https://%s/' % domain | ||||
|         resp = requests.get(url=url, headers={ | ||||
|             'User-Agent': USER_AGENT, | ||||
|         }) | ||||
|         resp.raise_for_status() | ||||
|         mf2 = mf2py.parse(resp.text, url=resp.url) | ||||
|         logging.info('Parsed mf2 for %s: %s', resp.url, json.dumps(mf2, indent=2)) | ||||
| 
 | ||||
|         hcard = mf2util.representative_hcard(mf2, resp.url) | ||||
|         logging.info('Representative h-card: %s', json.dumps(hcard, indent=2)) | ||||
| 
 | ||||
|         obj = microformats2.json_to_object(hcard) | ||||
|         obj.update({ | ||||
|             'inbox': '%s/%s/inbox' % (self.request.host_url, domain), | ||||
|         }) | ||||
|         logging.info('Returning: %s', json.dumps(obj, indent=2)) | ||||
| 
 | ||||
|         self.response.headers.update({ | ||||
|             'Content-Type': CONTENT_TYPE, | ||||
|             'Access-Control-Allow-Origin': '*', | ||||
|         }) | ||||
|         self.response.write(json.dumps(obj, indent=2)) | ||||
| 
 | ||||
| 
 | ||||
| app = webapp2.WSGIApplication( | ||||
|     [(r'/([^/]+\.[^/]+)/?', ActorHandler), | ||||
|     ], debug=appengine_config.DEBUG) | ||||
							
								
								
									
										6
									
								
								app.yaml
								
								
								
								
							
							
						
						
									
										6
									
								
								app.yaml
								
								
								
								
							|  | @ -10,6 +10,8 @@ builtins: | |||
| - remote_api: on | ||||
| 
 | ||||
| libraries: | ||||
| - name: lxml | ||||
|   version: latest | ||||
| - name: ssl | ||||
|   version: latest | ||||
| - name: webob | ||||
|  | @ -33,8 +35,8 @@ handlers: | |||
|   upload: static/index.html | ||||
| 
 | ||||
| # dynamic | ||||
| - url: /[^/]+ | ||||
|   script: app.application | ||||
| - url: /[^/]+/? | ||||
|   script: activitypub.app | ||||
|   secure: always | ||||
| 
 | ||||
| skip_files: | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| granary | ||||
| mf2py>=1.0.4 | ||||
| mf2util>=0.5.0 | ||||
| mock | ||||
| requests==2.10.0 | ||||
| requests-toolbelt==0.6.2 | ||||
| -e git+https://github.com/snarfed/webmention-tools.git#egg=webmentiontools | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| # webutil/test/__init__.py has setup code that makes App Engine SDK's | ||||
| # bundled libraries importable. | ||||
| import oauth_dropins.webutil.test | ||||
|  | @ -0,0 +1,38 @@ | |||
| # coding=utf-8 | ||||
| """Unit tests for activitypub.py. | ||||
| """ | ||||
| import json | ||||
| import unittest | ||||
| 
 | ||||
| import mock | ||||
| import requests | ||||
| 
 | ||||
| import activitypub | ||||
| 
 | ||||
| 
 | ||||
| @mock.patch('requests.get') | ||||
| class ActivityPubTest(unittest.TestCase): | ||||
| 
 | ||||
|     def test_actor_handler(self, mock_get): | ||||
|         html = u""" | ||||
| <body> | ||||
| <a class="h-card" rel="me" href="/about-me">Mrs. ☕ Foo</a> | ||||
| </body> | ||||
| """ | ||||
|         resp = requests.Response() | ||||
|         resp.status_code = 200 | ||||
|         resp._text = html | ||||
|         resp._content = html.encode('utf-8') | ||||
|         resp.encoding = 'utf-8' | ||||
|         resp.url = 'https://foo.com/' | ||||
|         mock_get.return_value = resp | ||||
| 
 | ||||
|         got = activitypub.app.get_response('/foo.com') | ||||
|         self.assertEquals(200, got.status_int) | ||||
|         self.assertEquals(activitypub.CONTENT_TYPE, got.headers['Content-Type']) | ||||
|         self.assertEquals({ | ||||
|             'objectType' : 'person', | ||||
|             'displayName': u'Mrs. ☕ Foo', | ||||
|             'url': 'https://foo.com/about-me', | ||||
|             'inbox': 'http://localhost/foo.com/inbox', | ||||
|         }, json.loads(got.body)) | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Ryan Barrett
						Ryan Barrett