mirror of
				https://git.sr.ht/~tsileo/microblog.pub
				synced 2025-06-05 21:59:23 +02:00 
			
		
		
		
	More progess on webmention replies
This commit is contained in:
		| @@ -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: | ||||
|   | ||||
							
								
								
									
										22
									
								
								app/main.py
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								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( | ||||
|                 ap_object=None, | ||||
|                 wm_reply=rep, | ||||
|                 is_requested=False, | ||||
|                 children=[], | ||||
|             )) | ||||
|             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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user