More progess on webmention replies
parent
066f5ec900
commit
9ee3f3b971
|
@ -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:
|
||||
|
|
14
app/main.py
14
app/main.py
|
@ -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,
|
||||
|
|
|
@ -541,3 +541,7 @@ a.label-btn {
|
|||
content: ': ';
|
||||
}
|
||||
}
|
||||
|
||||
.margin-top-20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue