From b977b64bfb4c2d9efb731dc57795b4c70b4bae15 Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Sun, 26 Jun 2022 10:01:26 +0200 Subject: [PATCH] Boostrap custom emoji support --- app/templates.py | 26 ++++++++++++++++++++++++-- app/templates/lookup.html | 2 +- app/templates/utils.html | 4 ++-- app/webfinger.py | 12 +++++++++--- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/app/templates.py b/app/templates.py index d519ff2..10e11de 100644 --- a/app/templates.py +++ b/app/templates.py @@ -10,12 +10,14 @@ import timeago # type: ignore from bs4 import BeautifulSoup # type: ignore from fastapi import Request from fastapi.templating import Jinja2Templates +from loguru import logger from sqlalchemy.orm import Session from starlette.templating import _TemplateResponse as TemplateResponse from app import models from app.actor import LOCAL_ACTOR from app.ap_object import Attachment +from app.ap_object import Object from app.boxes import public_outbox_objects_count from app.config import BASE_URL from app.config import DEBUG @@ -23,6 +25,7 @@ from app.config import VERSION from app.config import generate_csrf_token from app.config import session_serializer from app.database import now +from app.media import proxied_media_url from app.utils.highlight import HIGHLIGHT_CSS from app.utils.highlight import highlight @@ -160,10 +163,10 @@ def _update_inline_imgs(content): return soup.find("body").decode_contents() -def _clean_html(html: str) -> str: +def _clean_html(html: str, note: Object) -> str: try: return bleach.clean( - _update_inline_imgs(highlight(html)), + _replace_custom_emojis(_update_inline_imgs(highlight(html)), note), tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES, strip=True, @@ -194,6 +197,25 @@ def _pluralize(count: int, singular: str = "", plural: str = "s") -> str: return singular +def _replace_custom_emojis(content: str, note: Object) -> str: + idx = {} + for tag in note.ap_object.get("tag", []): + if tag.get("type") == "Emoji": + try: + idx[tag["name"]] = proxied_media_url(tag["icon"]["url"]) + except KeyError: + logger.warning(f"Failed to parse custom emoji {tag=}") + continue + + for emoji_name, emoji_url in idx.items(): + content = content.replace( + emoji_name, + f'{emoji_name}', # noqa: E501 + ) + + return content + + _templates.env.filters["domain"] = _filter_domain _templates.env.filters["media_proxy_url"] = _media_proxy_url _templates.env.filters["clean_html"] = _clean_html diff --git a/app/templates/lookup.html b/app/templates/lookup.html index d3ff8e6..f1d4835 100644 --- a/app/templates/lookup.html +++ b/app/templates/lookup.html @@ -9,6 +9,6 @@ {% if ap_object and ap_object.ap_type == "Person" %} {{ utils.display_actor(ap_object, actors_metadata) }} {% elif ap_object %} - {{ utils.display_object(ap_object) }} + {{ utils.display_object_expanded(ap_object) }} {% endif %} {% endblock %} diff --git a/app/templates/utils.html b/app/templates/utils.html index aaf3df7..da2b9f5 100644 --- a/app/templates/utils.html +++ b/app/templates/utils.html @@ -114,7 +114,7 @@ {{ display_actor(object.actor, {}) }}
-{{ object.content | clean_html | safe }} +{{ object.content | clean_html(object) | safe }}
{{ object.ap_published_at | format_date }} @@ -145,7 +145,7 @@ {{ object.ap_published_at | timeago }}
- {{ object.content | clean_html | safe }} + {{ object.content | clean_html(object) | safe }}
diff --git a/app/webfinger.py b/app/webfinger.py index 287b646..59b5199 100644 --- a/app/webfinger.py +++ b/app/webfinger.py @@ -4,7 +4,7 @@ from urllib.parse import urlparse import httpx from loguru import logger -from app import activitypub as ap +from app import config def webfinger( @@ -31,7 +31,13 @@ def webfinger( for i, proto in enumerate(protos): try: url = f"{proto}://{host}/.well-known/webfinger" - resp = ap.get(url, params={"resource": resource}) + resp = httpx.get( + url, + params={"resource": resource}, + headers={ + "User-Agent": config.USER_AGENT, + }, + ) break except httpx.HTTPStatusError as http_error: logger.exception("HTTP error") @@ -48,7 +54,7 @@ def webfinger( if is_404: return None - return resp + return resp.json() def get_remote_follow_template(resource: str) -> str | None: