improve rendering of ATProto interactions on user pages

for #825
pull/953/head
Ryan Barrett 2024-04-11 15:02:15 -07:00
rodzic 817ef1d5d6
commit 133d640f1d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
3 zmienionych plików z 51 dodań i 20 usunięć

Wyświetl plik

@ -54,6 +54,8 @@ _INSTANCE_ACTOR = None
# populated in User.status
WEB_OPT_OUT_DOMAINS = None
FEDI_URL_RE = re.compile(r'https://[^/]+/(@|users/)([^/@]+)(@[^/@]+)?(/(?:statuses/)?[0-9]+)?')
def instance_actor():
global _INSTANCE_ACTOR

Wyświetl plik

@ -47,6 +47,14 @@ appview = Client(f'https://{os.environ["APPVIEW_HOST"]}',
headers={'User-Agent': USER_AGENT})
LEXICONS = appview.defs
# https://atproto.com/guides/applications#record-types
COLLECTION_TO_TYPE = {
'app.bsky.actor.profile': 'profile',
'app.bsky.feed.like': 'like',
'app.bsky.feed.post': 'post',
'app.bsky.feed.repost': 'repost',
'app.bsky.graph.follow': 'follow',
}
DNS_GCP_PROJECT = 'brid-gy'
DNS_ZONE = 'brid-gy'
@ -55,6 +63,22 @@ logger.info(f'Using GCP DNS project {DNS_GCP_PROJECT} zone {DNS_ZONE}')
dns_client = dns.Client(project=DNS_GCP_PROJECT)
def did_to_handle(did):
"""Resolves a DID to a handle _if_ we have the DID doc stored locally.
Args:
did (str)
Returns:
str: handle, or None
"""
if did_obj := ATProto.load(did, did_doc=True):
if aka := util.get_first(did_obj.raw, 'alsoKnownAs', ''):
handle, _, _ = parse_at_uri(aka)
if handle:
return handle
class ATProto(User, Protocol):
"""AT Protocol class.
@ -86,11 +110,7 @@ class ATProto(User, Protocol):
@ndb.ComputedProperty
def handle(self):
"""Returns handle if the DID document includes one, otherwise None."""
if did_obj := ATProto.load(self.key.id(), did_doc=True):
if aka := util.get_first(did_obj.raw, 'alsoKnownAs', ''):
handle, _, _ = parse_at_uri(aka)
if handle:
return handle
return did_to_handle(self.key.id())
def web_url(self):
return bluesky.Bluesky.user_url(self.handle_or_id())

Wyświetl plik

@ -15,7 +15,7 @@ from Crypto.PublicKey import RSA
from flask import g, request
from google.cloud import ndb
from granary import as1, as2, atom, bluesky, microformats2
from granary.bluesky import BSKY_APP_URL_RE
from granary.bluesky import AT_URI_PATTERN, BSKY_APP_URL_RE
from granary.source import html_to_text
from oauth_dropins.webutil import util
from oauth_dropins.webutil.appengine_info import DEBUG
@ -1272,23 +1272,32 @@ def fetch_objects(query, by=None, user=None):
'url': id,
})
elif url:
# heuristics for sniffing Mastodon and similar fediverse URLs and
# converting them to more friendly @-names
# heuristics for sniffing URLs and converting them to more friendly
# phrases and user handles.
# TODO: standardize this into granary.as2 somewhere?
if not content:
fedi_url = re.match(
r'https://[^/]+/(@|users/)([^/@]+)(@[^/@]+)?(/(?:statuses/)?[0-9]+)?', url)
if fedi_url:
content = '@' + fedi_url.group(2)
if fedi_url.group(4):
content += "'s post"
from activitypub import FEDI_URL_RE
from atproto import COLLECTION_TO_TYPE, did_to_handle
if not content:
if bsky_url := BSKY_APP_URL_RE.match(url):
if handle := bsky_url.group('id'): # or DID
content = '@' + handle
if bsky_url.group('tid'):
content += "'s post"
if match := FEDI_URL_RE.match(url):
content = '@' + match.group(2)
if match.group(4):
content += "'s post"
elif match := BSKY_APP_URL_RE.match(url):
id = match.group('id')
if id.startswith('did:'):
id = ATdid_to_handle(id) or id
content = '@' + id
if match.group('tid'):
content += "'s post"
elif match := AT_URI_PATTERN.match(url):
id = match.group('repo')
if id.startswith('did:'):
id = did_to_handle(id) or id
content = '@' + id
if coll := match.group('collection'):
content += f"'s {COLLECTION_TO_TYPE.get(coll) or 'post'}"
url = bluesky.at_uri_to_web_url(url)
content = common.pretty_link(url, text=content, user=user)