From 3907ee1538161c8e6065115ce7333a10dfe4fdc6 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 16 May 2026 02:51:09 +0200 Subject: [PATCH] feat(activitypub): index hashtags from incoming federated notes --- crates/adapters/activitypub/src/handler.rs | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/adapters/activitypub/src/handler.rs b/crates/adapters/activitypub/src/handler.rs index faaa5d3..a2635bb 100644 --- a/crates/adapters/activitypub/src/handler.rs +++ b/crates/adapters/activitypub/src/handler.rs @@ -10,13 +10,14 @@ use url::Url; use crate::note::ThoughtNote; use crate::urls::ThoughtsUrls; use activitypub_base::{ActivityPubRepository, ApObjectHandler}; -use domain::ports::EventPublisher; +use domain::ports::{EventPublisher, TagRepository}; use domain::value_objects::UserId; pub struct ThoughtsObjectHandler { repo: Arc, urls: ThoughtsUrls, event_publisher: Option>, + tag_repo: Arc, } impl ThoughtsObjectHandler { @@ -24,11 +25,13 @@ impl ThoughtsObjectHandler { repo: Arc, base_url: &str, event_publisher: Option>, + tag_repo: Arc, ) -> Self { Self { repo, urls: ThoughtsUrls::new(base_url), event_publisher, + tag_repo, } } } @@ -138,7 +141,7 @@ impl ApObjectHandler for ThoughtsObjectHandler { "direct" }; - self.repo + let thought_id = self.repo .accept_note( ap_id.as_str(), &author_id, @@ -152,6 +155,22 @@ impl ApObjectHandler for ThoughtsObjectHandler { .await .map_err(|e| anyhow!("{e}"))?; + // Extract and index hashtags from the AP tag array. + let hashtag_names: Vec = note + .tag + .iter() + .filter(|t| t.get("type").and_then(|v| v.as_str()) == Some("Hashtag")) + .filter_map(|t| t.get("name").and_then(|v| v.as_str())) + .map(|name| name.trim_start_matches('#').to_lowercase()) + .filter(|name| !name.is_empty()) + .collect(); + + for name in hashtag_names { + if let Ok(tag) = self.tag_repo.find_or_create(&name).await { + let _ = self.tag_repo.attach_to_thought(&thought_id, tag.id).await; + } + } + // Fire mention notifications for local @mentions in the note's tag array. let base_url = url::Url::parse(&self.urls.base_url) .ok()