More progess on webmention replies

This commit is contained in:
Thomas Sileo 2022-11-19 08:12:33 +01:00
parent 066f5ec900
commit 9ee3f3b971
6 changed files with 75 additions and 17 deletions

View file

@ -42,8 +42,8 @@ from app.utils import webmentions
from app.utils.datetime import as_utc from app.utils.datetime import as_utc
from app.utils.datetime import now from app.utils.datetime import now
from app.utils.datetime import parse_isoformat from app.utils.datetime import parse_isoformat
from app.utils.text import slugify
from app.utils.facepile import WebmentionReply from app.utils.facepile import WebmentionReply
from app.utils.text import slugify
AnyboxObject = models.InboxObject | models.OutboxObject AnyboxObject = models.InboxObject | models.OutboxObject
@ -2592,7 +2592,7 @@ class ReplyTreeNode:
@property @property
def published_at(self) -> datetime.datetime: def published_at(self) -> datetime.datetime:
if self.ap_object: if self.ap_object:
return self.ap_object.ap_published_at return self.ap_object.ap_published_at # type: ignore
elif self.wm_reply: elif self.wm_reply:
return self.wm_reply.published_at return self.wm_reply.published_at
else: else:

View file

@ -74,8 +74,8 @@ from app.uploads import UPLOAD_DIR
from app.utils import pagination from app.utils import pagination
from app.utils.emoji import EMOJIS_BY_NAME from app.utils.emoji import EMOJIS_BY_NAME
from app.utils.facepile import Face from app.utils.facepile import Face
from app.utils.facepile import merge_faces
from app.utils.facepile import WebmentionReply from app.utils.facepile import WebmentionReply
from app.utils.facepile import merge_faces
from app.utils.highlight import HIGHLIGHT_CSS_HASH from app.utils.highlight import HIGHLIGHT_CSS_HASH
from app.utils.url import check_url from app.utils.url import check_url
from app.webfinger import get_remote_follow_template from app.webfinger import get_remote_follow_template
@ -837,19 +837,21 @@ def _merge_faces_from_inbox_object_and_webmentions(
def _merge_replies( def _merge_replies(
reply_tree_node: boxes.ReplyTreeNode, reply_tree_node: boxes.ReplyTreeNode,
webmentions: list[models.Webmention], webmentions: list[models.Webmention],
) -> None: ) -> boxes.ReplyTreeNode:
# TODO: return None as we update the object in place
webmention_replies = [] webmention_replies = []
for wm in [ for wm in [
wm for wm in webmentions wm for wm in webmentions if wm.webmention_type == models.WebmentionType.REPLY
if wm.webmention_type == models.WebmentionType.REPLY
]: ]:
if rep := WebmentionReply.from_webmention(wm): if rep := WebmentionReply.from_webmention(wm):
webmention_replies.append(boxes.ReplyTreeNode( webmention_replies.append(
boxes.ReplyTreeNode(
ap_object=None, ap_object=None,
wm_reply=rep, wm_reply=rep,
is_requested=False, is_requested=False,
children=[], children=[],
)) )
)
reply_tree_node.children = sorted( reply_tree_node.children = sorted(
reply_tree_node.children + webmention_replies, reply_tree_node.children + webmention_replies,

View file

@ -541,3 +541,7 @@ a.label-btn {
content: ': '; content: ': ';
} }
} }
.margin-top-20 {
margin-top: 20px;
}

View file

@ -335,6 +335,14 @@ def _clean_html(html: str, note: Object) -> str:
raise raise
def _clean_html_wm(html: str) -> str:
return bleach.clean(
html,
attributes=ALLOWED_ATTRIBUTES,
strip=True,
)
def _timeago(original_dt: datetime) -> str: def _timeago(original_dt: datetime) -> str:
dt = original_dt dt = original_dt
if dt.tzinfo: if dt.tzinfo:
@ -411,6 +419,7 @@ def _poll_item_pct(item: ap.RawObject, voters_count: int) -> int:
_templates.env.filters["domain"] = _filter_domain _templates.env.filters["domain"] = _filter_domain
_templates.env.filters["media_proxy_url"] = _media_proxy_url _templates.env.filters["media_proxy_url"] = _media_proxy_url
_templates.env.filters["clean_html"] = _clean_html _templates.env.filters["clean_html"] = _clean_html
_templates.env.filters["clean_html_wm"] = _clean_html_wm
_templates.env.filters["timeago"] = _timeago _templates.env.filters["timeago"] = _timeago
_templates.env.filters["format_date"] = _format_date _templates.env.filters["format_date"] = _format_date
_templates.env.filters["has_media_type"] = _has_media_type _templates.env.filters["has_media_type"] = _has_media_type

View file

@ -443,7 +443,40 @@
{% macro display_webmention_reply(wm_reply) %} {% macro display_webmention_reply(wm_reply) %}
{% block display_webmention_reply scoped %} {% block display_webmention_reply scoped %}
{{ wm_reply }}
<div class="ap-object">
<div class="actor-box h-card p-author">
<div class="icon-box">
<img src="{{ wm_reply.face.picture_url }}" alt="{{ wm_reply.face.name }}'s avatar" class="actor-icon u-photo">
</div>
<a href="{{ wm_reply.face.url }}" class="u-url">
<div><strong class="p-name">{{ wm_reply.face.name | clean_html_wm | safe }}</strong></div>
<div class="actor-handle">{{ wm_reply.face.url | truncate(64, True) }}</div>
</a>
</div>
<p class="in-reply-to">in reply to <a href="{{ wm_reply.in_reply_to }}" title="{{ wm_reply.in_reply_to }}" rel="nofollow">
this note
</a></p>
<div class="obj-content margin-top-20">
<div class="e-content">
{{ wm_reply.content | clean_html_wm | safe }}
</div>
</div>
<nav class="flexbox activity-bar margin-top-20">
<ul>
<li>
<div><a href="{{ wm_reply.url }}" rel="nofollow" class="object-permalink u-url u-uid">permalink</a></div>
</li>
<li>
<time class="dt-published" datetime="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}" title="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}">{{ wm_reply.published_at | timeago }}</time>
</li>
</ul>
</nav>
</div>
{% endblock %} {% endblock %}
{% endmacro %} {% endmacro %}

View file

@ -9,8 +9,8 @@ from app import media
from app.models import InboxObject from app.models import InboxObject
from app.models import Webmention from app.models import Webmention
from app.models import WebmentionType from app.models import WebmentionType
from app.utils.url import make_abs
from app.utils.datetime import parse_isoformat from app.utils.datetime import parse_isoformat
from app.utils.url import make_abs
@dataclass @dataclass
@ -40,7 +40,9 @@ class Face:
return cls( return cls(
ap_actor_id=None, ap_actor_id=None,
url=( url=(
item["properties"]["url"][0] if item["properties"].get("url") else webmention.source item["properties"]["url"][0]
if item["properties"].get("url")
else webmention.source
), ),
name=item["properties"]["name"][0], name=item["properties"]["name"][0],
picture_url=media.resized_media_url( picture_url=media.resized_media_url(
@ -95,7 +97,9 @@ def _parse_face(webmention: Webmention, items: list[dict[str, Any]]) -> Face | N
return Face( return Face(
ap_actor_id=None, ap_actor_id=None,
url=( url=(
items["properties"]["url"][0] if item["properties"].get("url") else webmention.source item["properties"]["url"][0]
if item["properties"].get("url")
else webmention.source
), ),
name=item["properties"]["name"][0], name=item["properties"]["name"][0],
picture_url=media.resized_media_url( picture_url=media.resized_media_url(
@ -112,6 +116,8 @@ def _parse_face(webmention: Webmention, items: list[dict[str, Any]]) -> Face | N
) )
break break
return None
@dataclass @dataclass
class WebmentionReply: class WebmentionReply:
@ -119,9 +125,10 @@ class WebmentionReply:
content: str content: str
url: str url: str
published_at: datetime.datetime published_at: datetime.datetime
in_reply_to: str
@classmethod @classmethod
def from_webmention(cls, webmention: Webmention) -> "WebmentionReply": def from_webmention(cls, webmention: Webmention) -> Optional["WebmentionReply"]:
if webmention.webmention_type != WebmentionType.REPLY: if webmention.webmention_type != WebmentionType.REPLY:
raise ValueError(f"Unexpected webmention {webmention.id}") raise ValueError(f"Unexpected webmention {webmention.id}")
@ -143,9 +150,12 @@ class WebmentionReply:
published_at=parse_isoformat( published_at=parse_isoformat(
item["properties"]["published"][0] item["properties"]["published"][0]
).replace(tzinfo=None), ).replace(tzinfo=None),
in_reply_to=webmention.target, # type: ignore
) )
except Exception: except Exception:
logger.exception( logger.exception(
f"Failed to build Face for webmention id={webmention.id}" f"Failed to build Face for webmention id={webmention.id}"
) )
break break
return None