diff --git a/activitypub.py b/activitypub.py index fcb04f3..4a21f43 100644 --- a/activitypub.py +++ b/activitypub.py @@ -28,7 +28,7 @@ from common import ( ) from models import Follower, Object, Target, User from protocol import Protocol -import webmention +import web logger = logging.getLogger(__name__) @@ -43,7 +43,7 @@ _DEFAULT_SIGNATURE_USER = None def default_signature_user(): global _DEFAULT_SIGNATURE_USER if _DEFAULT_SIGNATURE_USER is None: - _DEFAULT_SIGNATURE_USER = webmention.Webmention.get_or_create('snarfed.org') + _DEFAULT_SIGNATURE_USER = web.Web.get_or_create('snarfed.org') return _DEFAULT_SIGNATURE_USER @@ -54,7 +54,7 @@ class ActivityPub(User, Protocol): @classmethod def send(cls, obj, url, log_data=True): """Delivers an activity to an inbox URL.""" - # this is set in WebmentionView.try_activitypub() + # this is set in web.webmention_task() target = getattr(obj, 'target_as2', None) activity = obj.as2 or postprocess_as2(as2.from_as1(obj.as1), target=target) @@ -514,7 +514,7 @@ def actor(domain): error('', status=404) # TODO(#512): parameterize by protocol - g.user = webmention.Webmention.get_by_id(domain) + g.user = web.Web.get_by_id(domain) if not g.user: return f'Web user {domain} not found', 404 elif not g.user.actor_as2: @@ -567,7 +567,7 @@ def inbox(domain=None): # load user if domain: # TODO(#512): parameterize by protocol - g.user = webmention.Webmention.get_by_id(domain) + g.user = web.Web.get_by_id(domain) if not g.user: error(f'Web user {domain} not found', status=404) @@ -606,7 +606,7 @@ def follower_collection(domain, collection): https://www.w3.org/TR/activitystreams-core/#paging """ # TODO(#512): parameterize by protocol - if not webmention.Webmention.get_by_id(domain): + if not web.Web.get_by_id(domain): return f'Web user {domain} not found', 404 # page diff --git a/app.py b/app.py index 45da507..d958aec 100644 --- a/app.py +++ b/app.py @@ -6,7 +6,7 @@ registered. from flask_app import app # import all modules to register their Flask handlers -import activitypub, convert, follow, pages, redirect, superfeedr, ui, webfinger, webmention, xrpc_actor, xrpc_feed, xrpc_graph +import activitypub, convert, follow, pages, redirect, superfeedr, ui, webfinger, web, xrpc_actor, xrpc_feed, xrpc_graph import models models.reset_protocol_properties() diff --git a/common.py b/common.py index 4753c49..06bf933 100644 --- a/common.py +++ b/common.py @@ -185,5 +185,5 @@ def webmention_endpoint_cache_key(url): lock=threading.Lock(), info=True) def webmention_discover(url, **kwargs): - """Thin caching wrapper around :func:`webmention.discover`.""" + """Thin caching wrapper around :func:`web.discover`.""" return webmention.discover(url, **kwargs) diff --git a/convert.py b/convert.py index 8402d99..e769081 100644 --- a/convert.py +++ b/convert.py @@ -18,7 +18,7 @@ from activitypub import ActivityPub from common import CACHE_TIME from flask_app import app, cache from models import Object, PROTOCOLS -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -26,7 +26,7 @@ SOURCES = frozenset(( ActivityPub.LABEL, )) DESTS = frozenset(( - Webmention.LABEL, + Web.LABEL, )) diff --git a/follow.py b/follow.py index badeefa..5bb48f5 100644 --- a/follow.py +++ b/follow.py @@ -20,7 +20,7 @@ from activitypub import ActivityPub from flask_app import app import common import models -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -82,7 +82,7 @@ def remote_follow(): domain = request.values['domain'] # TODO(#512): parameterize by protocol - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: error(f'No web user found for domain {domain}') @@ -136,7 +136,7 @@ class FollowCallback(indieauth.Callback): domain = util.domain_from_link(me) # TODO(#512): parameterize by protocol - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: error(f'No web user for domain {domain}') domain = g.user.key.id() @@ -224,7 +224,7 @@ class UnfollowCallback(indieauth.Callback): domain = util.domain_from_link(me) # TODO(#512): parameterize by protocol - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: error(f'No web user for domain {domain}') domain = g.user.key.id() diff --git a/models.py b/models.py index 70eccf4..144208f 100644 --- a/models.py +++ b/models.py @@ -114,7 +114,7 @@ class User(StringIdModel, metaclass=ProtocolUserMeta): """Try to prevent instantiation. Use subclasses instead.""" raise NotImplementedError() - # TODO(#512): move this and is_homepage to webmention.py? + # TODO(#512): move this and is_homepage to web.py? @property def homepage(self): return f'https://{self.key.id()}/' diff --git a/pages.py b/pages.py index 550f2c5..c034e7f 100644 --- a/pages.py +++ b/pages.py @@ -18,7 +18,7 @@ from flask_app import app, cache import common from common import DOMAIN_RE from models import fetch_page, Follower, Object, PAGE_SIZE, User -from webmention import Webmention +from web import Web FOLLOWERS_UI_LIMIT = 999 @@ -59,7 +59,7 @@ def check_web_site(): flash(f'No domain found in {url}') return render_template('enter_web_site.html') - g.user = Webmention.get_or_create(domain) + g.user = Web.get_or_create(domain) try: g.user = g.user.verify() except BaseException as e: @@ -75,7 +75,7 @@ def check_web_site(): @app.get(f'/user/') def user(domain): - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: return USER_NOT_FOUND_HTML, 404 elif g.user.key.id() != domain: @@ -110,7 +110,7 @@ def user(domain): @app.get(f'/user//') def followers_or_following(domain, collection): - g.user = Webmention.get_by_id(domain) # g.user is used in template + g.user = Web.get_by_id(domain) # g.user is used in template if not g.user: return USER_NOT_FOUND_HTML, 404 @@ -139,7 +139,7 @@ def feed(domain): if format not in ('html', 'atom', 'rss'): error(f'format {format} not supported; expected html, atom, or rss') - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: return render_template('user_not_found.html', domain=domain), 404 diff --git a/protocol.py b/protocol.py index da7e71d..4e77f12 100644 --- a/protocol.py +++ b/protocol.py @@ -101,7 +101,7 @@ class Protocol: def serve(cls, obj): """Returns this protocol's Flask response for a given :class:`Object`. - For example, an HTML string and `'text/html'` for :class:`Webmention`, + For example, an HTML string and `'text/html'` for :class:`Web`, or a dict with AS2 JSON and `'application/activity+json'` for :class:`ActivityPub. @@ -355,8 +355,8 @@ class Protocol: try: # TODO: fix - from webmention import Webmention - if Webmention.send(obj, target.uri): + from web import Web + if Web.send(obj, target.uri): obj.delivered.append(target) if 'notification' not in obj.labels: obj.labels.append('notification') diff --git a/redirect.py b/redirect.py index 4736028..9da6a6e 100644 --- a/redirect.py +++ b/redirect.py @@ -25,7 +25,7 @@ from activitypub import ActivityPub from flask_app import app, cache from common import CACHE_TIME, CONTENT_TYPE_HTML from models import Object, User -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -78,7 +78,7 @@ def redir(to): if domain: # TODO(#512): do we need to parameterize this by protocol? or is it # only for web? - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if g.user: logger.info(f'Found web user for domain {domain}') break @@ -91,7 +91,7 @@ def redir(to): if accept_as2: # AS2 requested, fetch and convert and serve - obj = Webmention.load(to, check_backlink=False) + obj = Web.load(to, check_backlink=False) if not obj or obj.deleted: return f'Object not found: {to}', 404 ret, _ = ActivityPub.serve(obj) diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index 2c00497..68a20dc 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -28,7 +28,7 @@ import models from models import Follower, Object import protocol from protocol import Protocol -from webmention import Webmention +from web import Web from .testutil import Fake, TestCase diff --git a/tests/test_follow.py b/tests/test_follow.py index 3442167..1bf5955 100644 --- a/tests/test_follow.py +++ b/tests/test_follow.py @@ -14,7 +14,7 @@ from flask_app import app import common from common import redirect_unwrap from models import Follower, Object, User -from webmention import Webmention +from web import Web from . import testutil diff --git a/tests/test_pages.py b/tests/test_pages.py index a87273d..37ef405 100644 --- a/tests/test_pages.py +++ b/tests/test_pages.py @@ -18,9 +18,9 @@ from oauth_dropins.webutil.testutil import requests_response from flask_app import app import common from models import Object, Follower, User -from webmention import Webmention +from web import Web -from .test_webmention import ACTOR_AS2, ACTOR_HTML, ACTOR_MF2, REPOST_AS2 +from .test_web import ACTOR_AS2, ACTOR_HTML, ACTOR_MF2, REPOST_AS2 from .testutil import Fake, TestCase @@ -111,7 +111,7 @@ class PagesTest(TestCase): self.assert_equals(302, got.status_code) self.assert_equals('/user/user.com', got.headers['Location']) - user = Webmention.get_by_id('user.com') + user = Web.get_by_id('user.com') self.assertTrue(user.has_hcard) self.assertEqual('Person', user.actor_as2['type']) self.assertEqual('http://localhost/user.com', user.actor_as2['id']) @@ -120,7 +120,7 @@ class PagesTest(TestCase): got = self.client.post('/web-site', data={'url': '!!!'}) self.assert_equals(200, got.status_code) self.assertEqual(['No domain found in !!!'], get_flashed_messages()) - self.assertEqual(1, Webmention.query().count()) + self.assertEqual(1, Web.query().count()) @patch('requests.get') def test_check_web_site_fetch_fails(self, mock_get): diff --git a/tests/test_protocol.py b/tests/test_protocol.py index cb80443..4007226 100644 --- a/tests/test_protocol.py +++ b/tests/test_protocol.py @@ -9,7 +9,7 @@ import protocol from protocol import Protocol from flask_app import app from models import Follower, Object, PROTOCOLS, User -from webmention import Webmention +from web import Web from .test_activitypub import ACTOR, REPLY from .testutil import Fake, TestCase @@ -38,7 +38,7 @@ class ProtocolTest(TestCase): def test_protocols_global(self): self.assertEqual(Fake, PROTOCOLS['fake']) - self.assertEqual(Webmention, PROTOCOLS['webmention']) + self.assertEqual(Web, PROTOCOLS['webmention']) @patch('requests.get') def test_receive_reply_not_feed_not_notification(self, mock_get): diff --git a/tests/test_redirect.py b/tests/test_redirect.py index f8dbb39..deac985 100644 --- a/tests/test_redirect.py +++ b/tests/test_redirect.py @@ -10,7 +10,7 @@ import requests from flask_app import app, cache from common import redirect_unwrap from models import Object, User -from .test_webmention import ( +from .test_web import ( ACTOR_AS2, ACTOR_AS2_FULL, ACTOR_HTML, diff --git a/tests/test_webmention.py b/tests/test_web.py similarity index 98% rename from tests/test_webmention.py rename to tests/test_web.py index 43d096f..3b97c9b 100644 --- a/tests/test_webmention.py +++ b/tests/test_web.py @@ -23,7 +23,7 @@ from common import ( redirect_unwrap, ) from models import Follower, Object, Target, User -from webmention import TASKS_LOCATION, Webmention +from web import TASKS_LOCATION, Web from .test_activitypub import LIKE from . import testutil @@ -159,7 +159,7 @@ DELETE_AS2 = { @mock.patch('requests.post') @mock.patch('requests.get') -class WebmentionTest(testutil.TestCase): +class WebTest(testutil.TestCase): def setUp(self): super().setUp() g.user = self.user = self.make_user('user.com') @@ -1443,9 +1443,9 @@ http://this/404s got = www_user.verify() self.assertEqual('user.com', got.key.id()) - root_user = Webmention.get_by_id('user.com') + root_user = Web.get_by_id('user.com') self.assertEqual(root_user.key, www_user.key.get().use_instead) - self.assertEqual(root_user.key, Webmention.get_or_create('www.user.com').key) + self.assertEqual(root_user.key, Web.get_or_create('www.user.com').key) def test_verify_actor_rel_me_links(self, mock_get, _): mock_get.side_effect = [ @@ -1514,7 +1514,7 @@ http://this/404s @mock.patch('requests.post') @mock.patch('requests.get') -class WebmentionProtocolTest(testutil.TestCase): +class WebProtocolTest(testutil.TestCase): def setUp(self): super().setUp() @@ -1529,7 +1529,7 @@ class WebmentionProtocolTest(testutil.TestCase): mock_get.return_value = REPOST obj = Object(id='https://user.com/post') - Webmention.fetch(obj) + Web.fetch(obj) self.assert_equals({**REPOST_MF2, 'url': 'https://user.com/repost'}, obj.mf2) @@ -1538,7 +1538,7 @@ class WebmentionProtocolTest(testutil.TestCase): REPOST_HTML, content_type=CONTENT_TYPE_HTML, redirected_url='http://new/url') obj = Object(id='https://orig/url') - Webmention.fetch(obj) + Web.fetch(obj) self.assert_equals('http://new/url', obj.mf2['url']) self.assert_equals({**REPOST_MF2, 'url': 'http://new/url'}, obj.mf2) @@ -1547,14 +1547,14 @@ class WebmentionProtocolTest(testutil.TestCase): def test_fetch_error(self, mock_get, __): mock_get.return_value = requests_response(REPOST_HTML, status=405) with self.assertRaises(BadGateway) as e: - Webmention.fetch(Object(id='https://foo'), gateway=True) + Web.fetch(Object(id='https://foo'), gateway=True) def test_fetch_check_backlink_false(self, mock_get, mock_post): mock_get.return_value = requests_response( REPOST_HTML.replace('', '')) obj = Object(id='https://foo') - Webmention.fetch(obj, check_backlink=False) + Web.fetch(obj, check_backlink=False) self.assert_equals(REPOST_MF2, obj.mf2) mock_get.assert_has_calls((self.req('https://foo'),)) @@ -1571,14 +1571,14 @@ class WebmentionProtocolTest(testutil.TestCase): ] obj = Object(id='https://user.com/repost') - Webmention.fetch(obj) + Web.fetch(obj) self.assert_equals({**REPOST_MF2, 'url': 'https://user.com/repost'}, obj.mf2) def test_fetch_user_homepage(self, mock_get, __): mock_get.return_value = ACTOR obj = Object(id='https://user.com/') - Webmention.fetch(obj) + Web.fetch(obj) self.assert_equals({ **ACTOR_MF2_REL_URLS, @@ -1592,7 +1592,7 @@ class WebmentionProtocolTest(testutil.TestCase): obj = Object(id='https://user.com/') with self.assertRaises(BadRequest): - Webmention.fetch(obj) + Web.fetch(obj) def test_fetch_user_homepage_non_representative_hcard(self, mock_get, __): mock_get.return_value = requests_response( @@ -1601,14 +1601,14 @@ class WebmentionProtocolTest(testutil.TestCase): obj = Object(id='https://user.com/') with self.assertRaises(BadRequest): - Webmention.fetch(obj) + Web.fetch(obj) def test_send(self, mock_get, mock_post): mock_get.return_value = WEBMENTION_REL_LINK mock_post.return_value = requests_response() obj = Object(id='http://mas.to/like#ok', as2=LIKE, source_protocol='ui') - self.assertTrue(Webmention.send(obj, 'https://user.com/post')) + self.assertTrue(Web.send(obj, 'https://user.com/post')) self.assert_req(mock_get, 'https://user.com/post') args, kwargs = mock_post.call_args @@ -1622,14 +1622,14 @@ class WebmentionProtocolTest(testutil.TestCase): mock_get.return_value = WEBMENTION_NO_REL_LINK obj = Object(id='http://mas.to/like#ok', as2=LIKE) - self.assertFalse(Webmention.send(obj, 'https://user.com/post')) + self.assertFalse(Web.send(obj, 'https://user.com/post')) self.assert_req(mock_get, 'https://user.com/post') mock_post.assert_not_called() def test_serve(self, _, __): obj = Object(id='http://orig', mf2=ACTOR_MF2) - html, headers = Webmention.serve(obj) + html, headers = Web.serve(obj) self.assert_multiline_equals("""\ diff --git a/tests/test_webfinger.py b/tests/test_webfinger.py index 815a56f..d505e4f 100644 --- a/tests/test_webfinger.py +++ b/tests/test_webfinger.py @@ -10,7 +10,7 @@ from oauth_dropins.webutil.testutil import requests_response import common from models import User from . import testutil -from .test_webmention import ACTOR_HTML +from .test_web import ACTOR_HTML WEBFINGER = { 'subject': 'acct:user.com@user.com', diff --git a/tests/testutil.py b/tests/testutil.py index 9657724..096746c 100644 --- a/tests/testutil.py +++ b/tests/testutil.py @@ -30,7 +30,7 @@ import common import models from models import Object, PROTOCOLS, Target, User import protocol -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -128,7 +128,7 @@ class TestCase(unittest.TestCase, testutil.Asserts): # TODO(#512): switch default to Fake, start using that more @staticmethod - def make_user(domain, cls=Webmention, **kwargs): + def make_user(domain, cls=Web, **kwargs): """Reuse RSA key across Users because generating it is expensive.""" user = cls(id=domain, mod=global_user.mod, diff --git a/webmention.py b/web.py similarity index 97% rename from webmention.py rename to web.py index 6c95bf3..461ed5c 100644 --- a/webmention.py +++ b/web.py @@ -14,7 +14,7 @@ from oauth_dropins.webutil.appengine_config import tasks_client from oauth_dropins.webutil.appengine_info import APP_ID from oauth_dropins.webutil.flask_util import error, flash from oauth_dropins.webutil.util import json_dumps, json_loads -import oauth_dropins.webutil.webmention as webutil_webmention +from oauth_dropins.webutil import webmention from requests import HTTPError, RequestException, URLRequired from werkzeug.exceptions import BadGateway, BadRequest, HTTPException, NotFound @@ -37,8 +37,8 @@ WWW_DOMAINS = frozenset(( )) -class Webmention(User, Protocol): - """Webmention user and protocol implementation. +class Web(User, Protocol): + """Web user and webmention protocol implementation. The key name is the domain. """ @@ -52,7 +52,7 @@ class Webmention(User, Protocol): """Fetches site a couple ways to check for redirects and h-card. - Returns: :class:`Webmention` that was verified. May be different than + Returns: :class:`Web` that was verified. May be different than self! eg if self's domain started with www and we switch to the root domain. """ @@ -68,7 +68,7 @@ class Webmention(User, Protocol): resp = util.requests_get(root_site, gateway=False) if resp.ok and self.is_homepage(resp.url): logger.info(f'{root_site} redirects to {resp.url} ; using {root} instead') - root_user = Webmention.get_or_create(root) + root_user = Web.get_or_create(root) self.use_instead = root_user.key self.put() return root_user.verify() @@ -101,7 +101,7 @@ class Webmention(User, Protocol): # check home page try: - obj = Webmention.load(self.homepage, gateway=True) + obj = Web.load(self.homepage, gateway=True) self.actor_as2 = activitypub.postprocess_as2(as2.from_as1(obj.as1)) self.has_hcard = True except (BadRequest, NotFound): @@ -121,7 +121,7 @@ class Webmention(User, Protocol): endpoint = common.webmention_discover(url).endpoint if endpoint: - webutil_webmention.send(endpoint, source_url, url) + webmention.send(endpoint, source_url, url) return True @classmethod @@ -240,7 +240,7 @@ def webmention_external(): error(f'Bad URL {source}') domain = util.domain_from_link(source, minimize=False) - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: error(f'No user found for domain {domain}') @@ -288,13 +288,13 @@ def webmention_task(): domain = util.domain_from_link(source, minimize=False) logger.info(f'webmention from {domain}') - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if not g.user: error(f'No user found for domain {domain}', status=304) # fetch source page try: - obj = Webmention.load(source, refresh=True) + obj = Web.load(source, refresh=True) except BadRequest as e: error(str(e.description), status=304) except HTTPError as e: diff --git a/webfinger.py b/webfinger.py index cc32117..9702515 100644 --- a/webfinger.py +++ b/webfinger.py @@ -17,7 +17,7 @@ from oauth_dropins.webutil.util import json_dumps, json_loads from flask_app import app, cache import common from models import User -from webmention import Webmention +from web import Web NON_TLDS = frozenset(('html', 'json', 'php', 'xml')) @@ -45,7 +45,7 @@ class Actor(flask_util.XrdOrJrd): if domain.split('.')[-1] in NON_TLDS: error(f"{domain} doesn't look like a domain", status=404) - g.user = Webmention.get_by_id(domain) + g.user = Web.get_by_id(domain) if g.user: actor = g.user.to_as1() or {} homepage = g.user.homepage @@ -53,7 +53,7 @@ class Actor(flask_util.XrdOrJrd): actor_id = g.user.actor_id() elif external: g.external_user = homepage = f'https://{domain}/' - obj = Webmention.load(g.external_user) + obj = Web.load(g.external_user) actor = obj.as1 handle = f'@{domain}@{request.host}' actor_id = common.redirect_wrap(homepage) diff --git a/xrpc_actor.py b/xrpc_actor.py index a38541c..65800ae 100644 --- a/xrpc_actor.py +++ b/xrpc_actor.py @@ -10,7 +10,7 @@ from oauth_dropins.webutil import util from flask_app import xrpc_server from models import User -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -25,7 +25,7 @@ def getProfile(input, actor=None): if not actor or not re.match(util.DOMAIN_RE, actor): raise ValueError(f'{actor} is not a domain') - g.user = Webmention.get_by_id(actor) + g.user = Web.get_by_id(actor) if not g.user: raise ValueError(f'User {actor} not found') elif not g.user.actor_as2: diff --git a/xrpc_feed.py b/xrpc_feed.py index e496a47..b415780 100644 --- a/xrpc_feed.py +++ b/xrpc_feed.py @@ -10,7 +10,7 @@ from oauth_dropins.webutil import util from flask_app import xrpc_server from models import Object, PAGE_SIZE, User -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -23,7 +23,7 @@ def getAuthorFeed(input, author=None, limit=None, before=None): if not author or not re.match(util.DOMAIN_RE, author): raise ValueError(f'{author} is not a domain') - g.user = Webmention.get_by_id(author) + g.user = Web.get_by_id(author) if not g.user: raise ValueError(f'User {author} not found') elif not g.user.actor_as2: diff --git a/xrpc_graph.py b/xrpc_graph.py index de6c52b..48daacf 100644 --- a/xrpc_graph.py +++ b/xrpc_graph.py @@ -8,7 +8,7 @@ from oauth_dropins.webutil import util from flask_app import xrpc_server import common from models import Follower, User -from webmention import Webmention +from web import Web logger = logging.getLogger(__name__) @@ -26,7 +26,7 @@ def get_followers(query_prop, output_field, user=None, limit=50, before=None): # TODO: what is user? if not user or not re.match(util.DOMAIN_RE, user): raise ValueError(f'{user} is not a domain') - elif not Webmention.get_by_id(user): + elif not Web.get_by_id(user): raise ValueError(f'Unknown user {user}') collection = 'followers' if output_field == 'followers' else 'following'