2022-06-22 20:11:22 +02:00
|
|
|
import re
|
2022-08-24 20:12:10 +02:00
|
|
|
import typing
|
2022-06-22 20:11:22 +02:00
|
|
|
|
|
|
|
from markdown import markdown
|
2022-06-29 08:56:39 +02:00
|
|
|
from sqlalchemy import select
|
2022-06-22 20:11:22 +02:00
|
|
|
|
|
|
|
from app import webfinger
|
|
|
|
from app.config import BASE_URL
|
2022-06-29 20:43:17 +02:00
|
|
|
from app.database import AsyncSession
|
2022-06-27 20:55:44 +02:00
|
|
|
from app.utils import emoji
|
2022-06-22 20:11:22 +02:00
|
|
|
|
2022-08-24 20:12:10 +02:00
|
|
|
if typing.TYPE_CHECKING:
|
|
|
|
from app.actor import Actor
|
|
|
|
|
2022-06-22 20:11:22 +02:00
|
|
|
|
|
|
|
def _set_a_attrs(attrs, new=False):
|
|
|
|
attrs[(None, "target")] = "_blank"
|
|
|
|
attrs[(None, "class")] = "external"
|
|
|
|
attrs[(None, "rel")] = "noopener"
|
|
|
|
attrs[(None, "title")] = attrs[(None, "href")]
|
|
|
|
return attrs
|
|
|
|
|
|
|
|
|
|
|
|
_HASHTAG_REGEX = re.compile(r"(#[\d\w]+)")
|
|
|
|
_MENTION_REGEX = re.compile(r"@[\d\w_.+-]+@[\d\w-]+\.[\d\w\-.]+")
|
|
|
|
|
|
|
|
|
2022-08-24 20:12:10 +02:00
|
|
|
def hashtagify(content: str) -> tuple[str, list[dict[str, str]]]:
|
2022-06-22 20:11:22 +02:00
|
|
|
tags = []
|
|
|
|
hashtags = re.findall(_HASHTAG_REGEX, content)
|
|
|
|
hashtags = sorted(set(hashtags), reverse=True) # unique tags, longest first
|
|
|
|
for hashtag in hashtags:
|
|
|
|
tag = hashtag[1:]
|
|
|
|
link = f'<a href="{BASE_URL}/t/{tag}" class="mention hashtag" rel="tag">#<span>{tag}</span></a>' # noqa: E501
|
|
|
|
tags.append(dict(href=f"{BASE_URL}/t/{tag}", name=hashtag, type="Hashtag"))
|
|
|
|
content = content.replace(hashtag, link)
|
|
|
|
return content, tags
|
|
|
|
|
|
|
|
|
2022-06-29 20:43:17 +02:00
|
|
|
async def _mentionify(
|
|
|
|
db_session: AsyncSession,
|
2022-06-26 19:00:29 +02:00
|
|
|
content: str,
|
2022-08-24 20:12:10 +02:00
|
|
|
) -> tuple[str, list[dict[str, str]], list["Actor"]]:
|
|
|
|
from app import models
|
|
|
|
from app.actor import fetch_actor
|
|
|
|
|
2022-06-22 20:11:22 +02:00
|
|
|
tags = []
|
2022-06-26 19:00:29 +02:00
|
|
|
mentioned_actors = []
|
2022-06-22 20:11:22 +02:00
|
|
|
for mention in re.findall(_MENTION_REGEX, content):
|
|
|
|
_, username, domain = mention.split("@")
|
2022-06-29 20:43:17 +02:00
|
|
|
actor = (
|
|
|
|
await db_session.execute(
|
|
|
|
select(models.Actor).where(models.Actor.handle == mention)
|
|
|
|
)
|
2022-06-29 08:56:39 +02:00
|
|
|
).scalar_one_or_none()
|
2022-06-22 20:11:22 +02:00
|
|
|
if not actor:
|
2022-06-30 00:28:07 +02:00
|
|
|
actor_url = await webfinger.get_actor_url(mention)
|
2022-06-22 20:11:22 +02:00
|
|
|
if not actor_url:
|
|
|
|
# FIXME(ts): raise an error?
|
|
|
|
continue
|
2022-06-29 20:43:17 +02:00
|
|
|
actor = await fetch_actor(db_session, actor_url)
|
2022-06-22 20:11:22 +02:00
|
|
|
|
2022-06-26 19:00:29 +02:00
|
|
|
mentioned_actors.append(actor)
|
2022-08-09 22:22:58 +02:00
|
|
|
tags.append(dict(type="Mention", href=actor.ap_id, name=mention))
|
2022-06-22 20:11:22 +02:00
|
|
|
|
2022-08-11 20:27:17 +02:00
|
|
|
link = f'<span class="h-card"><a href="{actor.url}" class="u-url mention">{actor.handle}</a></span>' # noqa: E501
|
2022-06-22 20:11:22 +02:00
|
|
|
content = content.replace(mention, link)
|
2022-06-26 19:00:29 +02:00
|
|
|
return content, tags, mentioned_actors
|
2022-06-22 20:11:22 +02:00
|
|
|
|
|
|
|
|
2022-06-29 20:43:17 +02:00
|
|
|
async def markdownify(
|
|
|
|
db_session: AsyncSession,
|
2022-06-22 20:11:22 +02:00
|
|
|
content: str,
|
2022-08-24 20:12:10 +02:00
|
|
|
enable_mentionify: bool = True,
|
|
|
|
enable_hashtagify: bool = True,
|
|
|
|
) -> tuple[str, list[dict[str, str]], list["Actor"]]:
|
2022-06-22 20:11:22 +02:00
|
|
|
"""
|
|
|
|
>>> content, tags = markdownify("Hello")
|
|
|
|
|
|
|
|
"""
|
|
|
|
tags = []
|
2022-08-24 20:12:10 +02:00
|
|
|
mentioned_actors: list["Actor"] = []
|
|
|
|
if enable_hashtagify:
|
|
|
|
content, hashtag_tags = hashtagify(content)
|
2022-06-22 20:11:22 +02:00
|
|
|
tags.extend(hashtag_tags)
|
2022-08-24 20:12:10 +02:00
|
|
|
if enable_mentionify:
|
2022-06-29 20:43:17 +02:00
|
|
|
content, mention_tags, mentioned_actors = await _mentionify(db_session, content)
|
2022-06-22 20:11:22 +02:00
|
|
|
tags.extend(mention_tags)
|
2022-06-27 20:55:44 +02:00
|
|
|
|
|
|
|
# Handle custom emoji
|
|
|
|
tags.extend(emoji.tags(content))
|
|
|
|
|
2022-07-12 22:24:15 +02:00
|
|
|
content = markdown(content, extensions=["mdx_linkify", "fenced_code"])
|
2022-06-27 20:55:44 +02:00
|
|
|
|
2022-06-26 19:00:29 +02:00
|
|
|
return content, tags, mentioned_actors
|