From f6132a8e21aef93f11359048cf544bcad1f9a2fc Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Mon, 21 Nov 2022 19:59:27 -0700 Subject: [PATCH] Initial mentions-linking code --- activities/models/post.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/activities/models/post.py b/activities/models/post.py index c3de16f..b5cd4d6 100644 --- a/activities/models/post.py +++ b/activities/models/post.py @@ -1,9 +1,11 @@ +import re from typing import Dict, Optional import httpx import urlman from django.db import models, transaction from django.utils import timezone +from django.utils.safestring import mark_safe from activities.models.fan_out import FanOut from activities.models.timeline_event import TimelineEvent @@ -151,9 +153,44 @@ class Post(StatorModel): def get_absolute_url(self): return self.urls.view + ### Content cleanup and extraction ### + + mention_regex = re.compile( + r"([^\w\d\-_])(@[\w\d\-_]+(?:@[\w\d\-_]+\.[\w\d\-_\.]+)?)" + ) + + def linkify_mentions(self, content): + """ + Links mentions _in the context of the post_ - meaning that if there's + a short @andrew mention, it will look at the mentions link to resolve + it rather than presuming it's local. + """ + + def replacer(match): + print(match) + precursor = match.group(1) + handle = match.group(2) + # If the handle has no domain, try to match it with a mention + if "@" not in handle.lstrip("@"): + identity = self.mentions.filter(username=handle.lstrip("@")).first() + if identity: + url = identity.urls.view + else: + url = None + else: + url = f"/{handle}/" + # If we have a URL, link to it, otherwise don't link + if url: + return f"{precursor}{handle}" + else: + return match.group() + + print(f"replacing on {content!r}") + return mark_safe(self.mention_regex.sub(replacer, content)) + @property def safe_content(self): - return sanitize_post(self.content) + return self.linkify_mentions(sanitize_post(self.content)) ### Async helpers ###