feat(activitypub): implement on_like and on_announce_received in ThoughtsObjectHandler

This commit is contained in:
2026-05-15 04:55:50 +02:00
parent e691b20a05
commit a7527c50be
3 changed files with 86 additions and 4 deletions

View File

@@ -7,19 +7,25 @@ use url::Url;
use crate::note::ThoughtNote;
use crate::urls::ThoughtsUrls;
use activitypub_base::ApObjectHandler;
use domain::ports::ActivityPubRepository;
use domain::ports::{ActivityPubRepository, EventPublisher};
use domain::value_objects::UserId;
pub struct ThoughtsObjectHandler {
repo: Arc<dyn ActivityPubRepository>,
urls: ThoughtsUrls,
event_publisher: Option<Arc<dyn EventPublisher>>,
}
impl ThoughtsObjectHandler {
pub fn new(repo: Arc<dyn ActivityPubRepository>, base_url: &str) -> Self {
pub fn new(
repo: Arc<dyn ActivityPubRepository>,
base_url: &str,
event_publisher: Option<Arc<dyn EventPublisher>>,
) -> Self {
Self {
repo,
urls: ThoughtsUrls::new(base_url),
event_publisher,
}
}
}
@@ -170,11 +176,85 @@ impl ApObjectHandler for ThoughtsObjectHandler {
.map_err(|e| anyhow!("{e}"))
}
async fn on_like(&self, _object_url: &Url, _actor_url: &Url) -> Result<()> {
async fn on_like(&self, object_url: &Url, actor_url: &Url) -> Result<()> {
let thought_uuid = object_url
.path()
.strip_prefix("/thoughts/")
.and_then(|s| s.split('/').next())
.and_then(|s| uuid::Uuid::parse_str(s).ok());
let thought_uuid = match thought_uuid {
Some(u) => u,
None => {
tracing::debug!(object = %object_url, "on_like: not a local thought URL, skipping");
return Ok(());
}
};
let actor_user_id = self
.repo
.find_remote_actor_id(actor_url)
.await
.map_err(|e| anyhow!("{e}"))?;
let actor_user_id = match actor_user_id {
Some(id) => id,
None => {
tracing::debug!(actor = %actor_url, "on_like: remote actor not interned, skipping notification");
return Ok(());
}
};
if let Some(ep) = &self.event_publisher {
let thought_id = domain::value_objects::ThoughtId::from_uuid(thought_uuid);
let like_id = domain::value_objects::LikeId::new();
ep.publish(&domain::events::DomainEvent::LikeAdded {
like_id,
user_id: actor_user_id,
thought_id,
})
.await
.map_err(|e| anyhow!("{e}"))?;
}
Ok(())
}
async fn on_announce_received(&self, _object_url: &Url, _actor_url: &Url) -> Result<()> {
async fn on_announce_received(&self, object_url: &Url, actor_url: &Url) -> Result<()> {
let thought_uuid = object_url
.path()
.strip_prefix("/thoughts/")
.and_then(|s| s.split('/').next())
.and_then(|s| uuid::Uuid::parse_str(s).ok());
let thought_uuid = match thought_uuid {
Some(u) => u,
None => return Ok(()),
};
let actor_user_id = self
.repo
.find_remote_actor_id(actor_url)
.await
.map_err(|e| anyhow!("{e}"))?;
let actor_user_id = match actor_user_id {
Some(id) => id,
None => return Ok(()),
};
if let Some(ep) = &self.event_publisher {
let thought_id = domain::value_objects::ThoughtId::from_uuid(thought_uuid);
let boost_id = domain::value_objects::BoostId::new();
ep.publish(&domain::events::DomainEvent::BoostAdded {
boost_id,
user_id: actor_user_id,
thought_id,
})
.await
.map_err(|e| anyhow!("{e}"))?;
}
Ok(())
}