From eab6dbbe060b2ababf6e40880e94b9ea607cc8e5 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 8 May 2024 12:10:44 +0200 Subject: [PATCH] Fetch blocked objects if not known locally (fixes #4669) --- Cargo.lock | 4 +- Cargo.toml | 2 +- crates/apub/src/api/user_settings_backup.rs | 91 ++++++++++++++++++--- crates/apub/src/lib.rs | 2 +- 4 files changed, 83 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1747cb363..3da326101 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,7 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772" [[package]] name = "activitypub_federation" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54fe65c4a4b57712d8e436f1fb86ff37e10b56f011f4233fbbfa8c669163e9d" +version = "0.5.6" dependencies = [ "activitystreams-kinds", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index aec09093d..cd5e437f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ lemmy_db_views = { version = "=0.19.4-beta.6", path = "./crates/db_views" } lemmy_db_views_actor = { version = "=0.19.4-beta.6", path = "./crates/db_views_actor" } lemmy_db_views_moderator = { version = "=0.19.4-beta.6", path = "./crates/db_views_moderator" } lemmy_federate = { version = "=0.19.4-beta.6", path = "./crates/federate" } -activitypub_federation = { version = "0.5.5", default-features = false, features = [ +activitypub_federation = { path = "../activitypub-federation-rust", default-features = false, features = [ "actix-web", ] } diesel = "2.1.6" diff --git a/crates/apub/src/api/user_settings_backup.rs b/crates/apub/src/api/user_settings_backup.rs index 581db4e74..18f28e12d 100644 --- a/crates/apub/src/api/user_settings_backup.rs +++ b/crates/apub/src/api/user_settings_backup.rs @@ -277,9 +277,38 @@ pub async fn import_settings( // These tasks don't connect to any remote instances but only insert directly in the database. // That means the only error condition are db connection failures, so no extra error handling is // needed. + futures::stream::iter( + data + .blocked_communities + .clone() + .into_iter() + .map(|s| (s, context.reset_request_count())) + .map(|(blocked, context)| async move { + let community = blocked.dereference(&context).await?; + let form = CommunityBlockForm { + person_id, + community_id: community.id, + }; + CommunityBlock::block(&mut context.pool(), &form).await?; + LemmyResult::Ok(()) + }), + ) + .buffer_unordered(PARALLELISM) + .collect::>() + .await + .into_iter() + .enumerate() + .for_each(|(i, r)| { + if let Err(e) = r { + //failed_items.push(data.followed_communities.get(i).map(|u| u.inner().clone())); + //info!("Failed to import saved post community: {e}"); + } + }); + /* try_join_all(data.blocked_communities.iter().map(|blocked| async { - // dont fetch unknown blocked objects from home server - let community = blocked.dereference_local(&context).await?; + let context = context.reset_request_count(); + // Ignore fetch errors + let community = blocked.dereference(&context).await?; let form = CommunityBlockForm { person_id, community_id: community.id, @@ -288,21 +317,24 @@ pub async fn import_settings( LemmyResult::Ok(()) })) .await?; + */ try_join_all(data.blocked_users.iter().map(|blocked| async { - // dont fetch unknown blocked objects from home server - let target = blocked.dereference_local(&context).await?; - let form = PersonBlockForm { - person_id, - target_id: target.id, - }; - PersonBlock::block(&mut context.pool(), &form).await?; + let context = context.reset_request_count(); + // Ignore fetch errors + let target = blocked.dereference(&context).await.ok(); + if let Some(target) = target { + let form = PersonBlockForm { + person_id, + target_id: target.id, + }; + PersonBlock::block(&mut context.pool(), &form).await?; + } LemmyResult::Ok(()) })) .await?; try_join_all(data.blocked_instances.iter().map(|domain| async { - // dont fetch unknown blocked objects from home server let instance = Instance::read_or_create(&mut context.pool(), domain.clone()).await?; let form = InstanceBlockForm { person_id, @@ -324,7 +356,7 @@ pub async fn import_settings( mod tests { use crate::api::user_settings_backup::{export_settings, import_settings, UserSettingsBackup}; - use activitypub_federation::config::Data; + use activitypub_federation::config::Data;use lemmy_db_views_actor::structs::CommunityBlockView; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{ source::{ @@ -494,4 +526,41 @@ mod tests { LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?; Ok(()) } + + + #[tokio::test] + #[serial] + async fn test_settings_fetch_and_import() -> LemmyResult<()> { + let context = LemmyContext::init_test_context().await; + + let backup: UserSettingsBackup = serde_json::from_str( + r#"{"blocked_communities": [ + "https://slrpnk.net/c/memes", + "https://lemmy.world/c/atheism", + "https://midwest.social/c/religiouscringe" + ] + }"#, + ) + .unwrap(); + let import_user = create_user("charles".to_string(), None, &context).await?; + + import_settings( + actix_web::web::Json(backup), + import_user.clone(), + context.reset_request_count(), + ) + .await?; + + // wait for background task to finish + sleep(Duration::from_millis(1000)).await; + + let blocks = CommunityBlockView::for_person( + &mut context.pool(), + import_user.person.id, + ) + .await?; + assert_eq!(blocks.len(), 3); + LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?; + Ok(()) + } } diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index a5643b95c..5f3603bb3 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -29,7 +29,7 @@ pub(crate) mod mentions; pub mod objects; pub mod protocol; -pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 50; +pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 100; /// Only include a basic context to save space and bandwidth. The main context is hosted statically /// on join-lemmy.org. Include activitystreams explicitly for better compat, but this could