diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c5718d..3c596d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Make webfinger response compatible with GNU Social account lookup. - Prefer `Group` actor when doing webfinger query on Lemmy server. - Fetch missing profiles before doing follower migration. +- Follow FEP-e232 links when importing post. ## [1.14.0] - 2023-02-22 diff --git a/src/activitypub/fetcher/helpers.rs b/src/activitypub/fetcher/helpers.rs index 338fa76..24f8012 100644 --- a/src/activitypub/fetcher/helpers.rs +++ b/src/activitypub/fetcher/helpers.rs @@ -5,7 +5,7 @@ use mitra_config::{Config, Instance}; use crate::activitypub::{ actors::helpers::{create_remote_profile, update_remote_profile}, - handlers::create::handle_note, + handlers::create::{get_object_links, handle_note}, identifiers::parse_local_object_id, receiver::HandlerError, types::Object, @@ -192,6 +192,7 @@ pub async fn import_post( let object_id = match queue.pop() { Some(object_id) => { if objects.iter().any(|object| object.id == object_id) { + // Can happen due to redirections log::warn!("loop detected"); continue; }; @@ -253,9 +254,9 @@ pub async fn import_post( // Fetch parent object on next iteration queue.push(object_id.to_owned()); }; - if let Some(ref object_id) = object.quote_url { - // Fetch quoted object after fetching current thread - queue.insert(0, object_id.to_owned()); + for object_id in get_object_links(&object)? { + // Fetch linked objects after fetching current thread + queue.insert(0, object_id); }; maybe_object = None; objects.push(object); diff --git a/src/activitypub/handlers/create.rs b/src/activitypub/handlers/create.rs index 89a51bc..f79441e 100644 --- a/src/activitypub/handlers/create.rs +++ b/src/activitypub/handlers/create.rs @@ -197,6 +197,43 @@ pub async fn get_object_attachments( Ok((attachments, unprocessed)) } +pub fn get_object_links( + object: &Object, +) -> Result, HandlerError> { + let mut links = vec![]; + if let Some(ref value) = object.tag { + let list: Vec = parse_property_value(value) + .map_err(|_| ValidationError("invalid tag property"))?; + for tag_value in list { + let tag_type = tag_value["type"].as_str().unwrap_or(HASHTAG); + if tag_type == LINK { + let tag: LinkTag = match serde_json::from_value(tag_value) { + Ok(tag) => tag, + Err(_) => { + log::warn!("invalid link tag"); + continue; + }, + }; + if tag.media_type != AP_MEDIA_TYPE && + tag.media_type != AS_MEDIA_TYPE + { + // Unknown media type + continue; + }; + if !links.contains(&tag.href) { + links.push(tag.href); + }; + }; + }; + }; + if let Some(ref object_id) = object.quote_url { + if !links.contains(object_id) { + links.push(object_id.to_owned()); + }; + }; + Ok(links) +} + pub async fn get_object_tags( config: &Config, db_client: &impl DatabaseClient,