feat: add ApVisibility (Public/FollowersOnly/Private) to broadcast_create_note and broadcast_update_note
This commit is contained in:
@@ -25,7 +25,7 @@ pub use repository::{
|
|||||||
BlockedDomain, FederationRepository, Follower, FollowerStatus, FollowingStatus, RemoteActor,
|
BlockedDomain, FederationRepository, Follower, FollowerStatus, FollowingStatus, RemoteActor,
|
||||||
};
|
};
|
||||||
pub use service::ActivityPubService;
|
pub use service::ActivityPubService;
|
||||||
pub use user::{ApActorType, ApProfileField, ApUser, ApUserRepository, LookedUpActor};
|
pub use user::{ApActorType, ApProfileField, ApUser, ApUserRepository, ApVisibility, LookedUpActor};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "tests/integration.rs"]
|
#[path = "tests/integration.rs"]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
actors::get_local_actor,
|
actors::get_local_actor,
|
||||||
urls::activity_url,
|
urls::activity_url,
|
||||||
|
user::ApVisibility,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ActivityPubService;
|
use super::ActivityPubService;
|
||||||
@@ -168,7 +169,11 @@ impl ActivityPubService {
|
|||||||
&self,
|
&self,
|
||||||
local_user_id: uuid::Uuid,
|
local_user_id: uuid::Uuid,
|
||||||
note: serde_json::Value,
|
note: serde_json::Value,
|
||||||
|
visibility: ApVisibility,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if visibility == ApVisibility::Private {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let data = self.federation_config.to_request_data();
|
let data = self.federation_config.to_request_data();
|
||||||
let Some((local_actor, inboxes)) = self.accepted_follower_inboxes(&data, local_user_id).await? else { return Ok(()); };
|
let Some((local_actor, inboxes)) = self.accepted_follower_inboxes(&data, local_user_id).await? else { return Ok(()); };
|
||||||
let note_id_str = note["id"].as_str().unwrap_or("");
|
let note_id_str = note["id"].as_str().unwrap_or("");
|
||||||
@@ -177,13 +182,14 @@ impl ActivityPubService {
|
|||||||
self.base_url,
|
self.base_url,
|
||||||
uuid::Uuid::new_v5(&uuid::Uuid::NAMESPACE_URL, note_id_str.as_bytes())
|
uuid::Uuid::new_v5(&uuid::Uuid::NAMESPACE_URL, note_id_str.as_bytes())
|
||||||
)).map_err(|e| anyhow::anyhow!("{e}"))?;
|
)).map_err(|e| anyhow::anyhow!("{e}"))?;
|
||||||
|
let (to, cc) = visibility_addressing(visibility, &local_actor.followers_url);
|
||||||
let create = CreateActivity {
|
let create = CreateActivity {
|
||||||
id: create_id,
|
id: create_id,
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
actor: ObjectId::from(local_actor.ap_id.clone()),
|
actor: ObjectId::from(local_actor.ap_id.clone()),
|
||||||
object: note,
|
object: note,
|
||||||
to: vec![crate::urls::AS_PUBLIC.to_string()],
|
to,
|
||||||
cc: vec![local_actor.followers_url.to_string()],
|
cc,
|
||||||
bto: vec![],
|
bto: vec![],
|
||||||
bcc: vec![],
|
bcc: vec![],
|
||||||
};
|
};
|
||||||
@@ -195,16 +201,21 @@ impl ActivityPubService {
|
|||||||
&self,
|
&self,
|
||||||
local_user_id: uuid::Uuid,
|
local_user_id: uuid::Uuid,
|
||||||
note: serde_json::Value,
|
note: serde_json::Value,
|
||||||
|
visibility: ApVisibility,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if visibility == ApVisibility::Private {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let data = self.federation_config.to_request_data();
|
let data = self.federation_config.to_request_data();
|
||||||
let Some((local_actor, inboxes)) = self.accepted_follower_inboxes(&data, local_user_id).await? else { return Ok(()); };
|
let Some((local_actor, inboxes)) = self.accepted_follower_inboxes(&data, local_user_id).await? else { return Ok(()); };
|
||||||
|
let (to, cc) = visibility_addressing(visibility, &local_actor.followers_url);
|
||||||
let update = crate::activities::UpdateActivity {
|
let update = crate::activities::UpdateActivity {
|
||||||
id: activity_url(&self.base_url).map_err(|e| anyhow::anyhow!("{e}"))?,
|
id: activity_url(&self.base_url).map_err(|e| anyhow::anyhow!("{e}"))?,
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
actor: ObjectId::from(local_actor.ap_id.clone()),
|
actor: ObjectId::from(local_actor.ap_id.clone()),
|
||||||
object: note,
|
object: note,
|
||||||
to: vec![crate::urls::AS_PUBLIC.to_string()],
|
to,
|
||||||
cc: vec![local_actor.followers_url.to_string()],
|
cc,
|
||||||
};
|
};
|
||||||
let (json, sends, inboxes) = self.prepare_broadcast(&data, &local_actor, inboxes, update).await?;
|
let (json, sends, inboxes) = self.prepare_broadcast(&data, &local_actor, inboxes, update).await?;
|
||||||
self.dispatch_deliveries(&data, &local_actor, inboxes, sends, json).await
|
self.dispatch_deliveries(&data, &local_actor, inboxes, sends, json).await
|
||||||
@@ -257,3 +268,22 @@ impl ActivityPubService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `(to, cc)` addressing for the given visibility.
|
||||||
|
/// `Private` is handled before calling this (early return in broadcast methods).
|
||||||
|
pub(super) fn visibility_addressing(
|
||||||
|
visibility: ApVisibility,
|
||||||
|
followers_url: &Url,
|
||||||
|
) -> (Vec<String>, Vec<String>) {
|
||||||
|
match visibility {
|
||||||
|
ApVisibility::Public => (
|
||||||
|
vec![crate::urls::AS_PUBLIC.to_string()],
|
||||||
|
vec![followers_url.to_string()],
|
||||||
|
),
|
||||||
|
ApVisibility::FollowersOnly => (
|
||||||
|
vec![followers_url.to_string()],
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
|
ApVisibility::Private => (vec![], vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
16
src/user.rs
16
src/user.rs
@@ -8,6 +8,22 @@ pub struct ApProfileField {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Visibility of a federated post.
|
||||||
|
///
|
||||||
|
/// Controls the `to`/`cc` addressing fields of outbound Create/Update activities
|
||||||
|
/// and whether the library fans the activity out to followers at all.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
|
pub enum ApVisibility {
|
||||||
|
/// `to: [AS_PUBLIC], cc: [followers]` — fully public, indexable by search engines.
|
||||||
|
#[default]
|
||||||
|
Public,
|
||||||
|
/// `to: [followers], cc: []` — only followers receive it, not indexed publicly.
|
||||||
|
FollowersOnly,
|
||||||
|
/// No federation delivery. The library returns immediately without sending anything.
|
||||||
|
/// Use when the post should exist only on the local instance.
|
||||||
|
Private,
|
||||||
|
}
|
||||||
|
|
||||||
/// Actor type for AP serialization. Defaults to `Person`.
|
/// Actor type for AP serialization. Defaults to `Person`.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ApActorType {
|
pub enum ApActorType {
|
||||||
|
|||||||
Reference in New Issue
Block a user