More progess on webmention replies

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

View File

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

View File

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

View File

@ -335,6 +335,14 @@ def _clean_html(html: str, note: Object) -> str:
raise
def _clean_html_wm(html: str) -> str:
return bleach.clean(
html,
attributes=ALLOWED_ATTRIBUTES,
strip=True,
)
def _timeago(original_dt: datetime) -> str:
dt = original_dt
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["media_proxy_url"] = _media_proxy_url
_templates.env.filters["clean_html"] = _clean_html
_templates.env.filters["clean_html_wm"] = _clean_html_wm
_templates.env.filters["timeago"] = _timeago
_templates.env.filters["format_date"] = _format_date
_templates.env.filters["has_media_type"] = _has_media_type

View File

@ -443,7 +443,40 @@
{% macro display_webmention_reply(wm_reply) %}
{% 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 %}
{% endmacro %}

View File

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