Rewrite remaining activities

This commit is contained in:
Felix Ableitner 2021-08-15 00:33:01 +02:00
parent 12a55ce63f
commit 4e840a9527
17 changed files with 252 additions and 417 deletions

View file

@ -8,12 +8,14 @@ use lemmy_api_common::{
get_local_user_view_from_jwt,
is_mod_or_admin,
};
use lemmy_apub::{
activities::following::{
follow::FollowCommunity as FollowCommunityApub,
undo::UndoFollowCommunity,
use lemmy_apub::activities::{
community::{
add_mod::AddMod,
block_user::BlockUserFromCommunity,
remove_mod::RemoveMod,
undo_block_user::UndoBlockUserFromCommunity,
},
CommunityType,
following::{follow::FollowCommunity as FollowCommunityApub, undo::UndoFollowCommunity},
};
use lemmy_db_queries::{
source::{comment::Comment_, community::CommunityModerator_, post::Post_},
@ -157,17 +159,20 @@ impl Perform for BanFromCommunity {
.await?
.ok();
community
.send_block_user(&local_user_view.person, banned_person, context)
BlockUserFromCommunity::send(&community, &banned_person, &local_user_view.person, context)
.await?;
} else {
let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form);
if blocking(context.pool(), unban).await?.is_err() {
return Err(ApiError::err("community_user_already_banned").into());
}
community
.send_undo_block_user(&local_user_view.person, banned_person, context)
.await?;
UndoBlockUserFromCommunity::send(
&community,
&banned_person,
&local_user_view.person,
context,
)
.await?;
}
// Remove/Restore their data if that's desired
@ -294,13 +299,9 @@ impl Perform for AddModToCommunity {
})
.await??;
if data.added {
community
.send_add_mod(&local_user_view.person, updated_mod, context)
.await?;
AddMod::send(&community, &updated_mod, &local_user_view.person, context).await?;
} else {
community
.send_remove_mod(&local_user_view.person, updated_mod, context)
.await?;
RemoveMod::send(&community, &updated_mod, &local_user_view.person, context).await?;
}
// Note: in case a remote mod is added, this returns the old moderators list, it will only get

View file

@ -5,7 +5,7 @@ use lemmy_api_common::{
community::{CommunityResponse, EditCommunity},
get_local_user_view_from_jwt,
};
use lemmy_apub::CommunityType;
use lemmy_apub::activities::community::update::UpdateCommunity;
use lemmy_db_queries::{diesel_option_overwrite_to_url, Crud};
use lemmy_db_schema::{
naive_now,
@ -69,9 +69,7 @@ impl PerformCrud for EditCommunity {
.await?
.map_err(|_| ApiError::err("couldnt_update_community"))?;
updated_community
.send_update(local_user_view.person.to_owned(), context)
.await?;
UpdateCommunity::send(&updated_community, &local_user_view.person, context).await?;
let op = UserOperationCrud::EditCommunity;
send_community_ws_message(data.community_id, op, websocket_id, None, context).await

View file

@ -1,18 +1,26 @@
use crate::{
activities::{
community::announce::AnnouncableActivities,
generate_activity_id,
verify_activity,
verify_add_remove_moderator_target,
verify_mod_action,
verify_person_in_community,
},
activity_queue::send_to_community_new,
extensions::context::lemmy_context,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
CommunityType,
generate_moderators_url,
ActorType,
};
use activitystreams::{activity::kind::AddType, base::AnyBase};
use activitystreams::activity::kind::AddType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::{source::community::CommunityModerator_, Joinable};
use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm};
use lemmy_db_schema::source::{
community::{Community, CommunityModerator, CommunityModeratorForm},
person::Person,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
@ -30,6 +38,34 @@ pub struct AddMod {
common: ActivityCommonFields,
}
impl AddMod {
pub async fn send(
community: &Community,
added_mod: &Person,
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let id = generate_activity_id(AddType::Add)?;
let add = AddMod {
to: PublicUrl::Public,
object: added_mod.actor_id(),
target: generate_moderators_url(&community.actor_id)?.into(),
cc: [community.actor_id()],
kind: AddType::Add,
common: ActivityCommonFields {
context: lemmy_context(),
id: id.clone(),
actor: actor.actor_id(),
unparsed: Default::default(),
},
};
let activity = AnnouncableActivities::AddMod(add);
let inboxes = vec![added_mod.get_shared_inbox_or_inbox_url()];
send_to_community_new(activity, &id, actor, community, inboxes, context).await
}
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for AddMod {
async fn verify(
@ -70,12 +106,6 @@ impl ActivityHandler for AddMod {
})
.await??;
}
if community.local {
let anybase = AnyBase::from_arbitrary_json(serde_json::to_string(&self)?)?;
community
.send_announce(anybase, Some(self.object.clone()), context)
.await?;
}
// TODO: send websocket notification about added mod
Ok(())
}

View file

@ -5,12 +5,14 @@ use crate::{
add_mod::AddMod,
block_user::BlockUserFromCommunity,
list_community_follower_inboxes,
remove_mod::RemoveMod,
undo_block_user::UndoBlockUserFromCommunity,
update::UpdateCommunity,
},
deletion::{delete::Delete, undo_delete::UndoDelete},
generate_activity_id,
post::create_or_update::CreateOrUpdatePost,
removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
undo_remove::UndoRemovePostCommentOrCommunity,
verify_activity,
verify_community,
voting::{undo_vote::UndoVote, vote::Vote},
@ -40,6 +42,7 @@ pub enum AnnouncableActivities {
Delete(Delete),
UndoDelete(UndoDelete),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),

View file

@ -1,16 +1,29 @@
use crate::{
activities::{verify_activity, verify_mod_action, verify_person_in_community},
activities::{
community::announce::AnnouncableActivities,
generate_activity_id,
verify_activity,
verify_mod_action,
verify_person_in_community,
},
activity_queue::send_to_community_new,
extensions::context::lemmy_context,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
ActorType,
};
use activitystreams::activity::kind::BlockType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::{Bannable, Followable};
use lemmy_db_schema::source::community::{
CommunityFollower,
CommunityFollowerForm,
CommunityPersonBan,
CommunityPersonBanForm,
use lemmy_db_schema::source::{
community::{
Community,
CommunityFollower,
CommunityFollowerForm,
CommunityPersonBan,
CommunityPersonBanForm,
},
person::Person,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
@ -28,6 +41,42 @@ pub struct BlockUserFromCommunity {
common: ActivityCommonFields,
}
impl BlockUserFromCommunity {
pub(in crate::activities::community) fn new(
id: Url,
community: &Community,
target: &Person,
actor: &Person,
) -> BlockUserFromCommunity {
BlockUserFromCommunity {
to: PublicUrl::Public,
object: target.actor_id(),
cc: [community.actor_id()],
kind: BlockType::Block,
common: ActivityCommonFields {
context: lemmy_context(),
id,
actor: actor.actor_id(),
unparsed: Default::default(),
},
}
}
pub async fn send(
community: &Community,
target: &Person,
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let id = generate_activity_id(BlockType::Block)?;
let block = BlockUserFromCommunity::new(id.clone(), community, target, actor);
let activity = AnnouncableActivities::BlockUserFromCommunity(block);
let inboxes = vec![target.get_shared_inbox_or_inbox_url()];
send_to_community_new(activity, &id, actor, community, inboxes, context).await
}
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for BlockUserFromCommunity {
async fn verify(

View file

@ -8,6 +8,7 @@ use url::Url;
pub mod add_mod;
pub mod announce;
pub mod block_user;
pub mod remove_mod;
pub mod undo_block_user;
pub mod update;

View file

@ -1,19 +1,27 @@
use crate::{
activities::{
community::announce::AnnouncableActivities,
deletion::{delete::receive_remove_action, verify_delete_activity},
generate_activity_id,
verify_activity,
verify_add_remove_moderator_target,
verify_mod_action,
verify_person_in_community,
},
activity_queue::send_to_community_new,
extensions::context::lemmy_context,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
CommunityType,
generate_moderators_url,
ActorType,
};
use activitystreams::{activity::kind::RemoveType, base::AnyBase};
use activitystreams::activity::kind::RemoveType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::Joinable;
use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm};
use lemmy_db_schema::source::{
community::{Community, CommunityModerator, CommunityModeratorForm},
person::Person,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
@ -22,16 +30,44 @@ use url::Url;
#[serde(rename_all = "camelCase")]
pub struct RemoveMod {
to: PublicUrl,
pub(in crate::activities::removal) object: Url,
pub(in crate::activities) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
// if target is set, this is means remove mod from community
pub(in crate::activities::removal) target: Option<Url>,
pub(in crate::activities) target: Option<Url>,
#[serde(flatten)]
common: ActivityCommonFields,
}
impl RemoveMod {
pub async fn send(
community: &Community,
removed_mod: &Person,
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let id = generate_activity_id(RemoveType::Remove)?;
let remove = RemoveMod {
to: PublicUrl::Public,
object: removed_mod.actor_id(),
target: Some(generate_moderators_url(&community.actor_id)?.into()),
cc: [community.actor_id()],
kind: RemoveType::Remove,
common: ActivityCommonFields {
context: lemmy_context(),
id: id.clone(),
actor: actor.actor_id(),
unparsed: Default::default(),
},
};
let activity = AnnouncableActivities::RemoveMod(remove);
let inboxes = vec![removed_mod.get_shared_inbox_or_inbox_url()];
send_to_community_new(activity, &id, actor, community, inboxes, context).await
}
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for RemoveMod {
async fn verify(
@ -77,10 +113,6 @@ impl ActivityHandler for RemoveMod {
CommunityModerator::leave(conn, &form)
})
.await??;
let anybase = AnyBase::from_arbitrary_json(serde_json::to_string(&self)?)?;
community
.send_announce(anybase, Some(self.object.clone()), context)
.await?;
// TODO: send websocket notification about removed mod
Ok(())
} else {

View file

@ -1,17 +1,24 @@
use crate::{
activities::{
community::block_user::BlockUserFromCommunity,
community::{announce::AnnouncableActivities, block_user::BlockUserFromCommunity},
generate_activity_id,
verify_activity,
verify_mod_action,
verify_person_in_community,
},
activity_queue::send_to_community_new,
extensions::context::lemmy_context,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
ActorType,
};
use activitystreams::activity::kind::UndoType;
use activitystreams::activity::kind::{BlockType, UndoType};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::Bannable;
use lemmy_db_schema::source::community::{CommunityPersonBan, CommunityPersonBanForm};
use lemmy_db_schema::source::{
community::{Community, CommunityPersonBan, CommunityPersonBanForm},
person::Person,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
@ -28,6 +35,40 @@ pub struct UndoBlockUserFromCommunity {
common: ActivityCommonFields,
}
impl UndoBlockUserFromCommunity {
pub async fn send(
community: &Community,
target: &Person,
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let block = BlockUserFromCommunity::new(
generate_activity_id(BlockType::Block)?,
community,
target,
actor,
);
let id = generate_activity_id(UndoType::Undo)?;
let undo = UndoBlockUserFromCommunity {
to: PublicUrl::Public,
object: block,
cc: [community.actor_id()],
kind: UndoType::Undo,
common: ActivityCommonFields {
context: lemmy_context(),
id: id.clone(),
actor: actor.actor_id(),
unparsed: Default::default(),
},
};
let activity = AnnouncableActivities::UndoBlockUserFromCommunity(undo);
let inboxes = vec![target.get_shared_inbox_or_inbox_url()];
send_to_community_new(activity, &id, actor, community, inboxes, context).await
}
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoBlockUserFromCommunity {
async fn verify(

View file

@ -1,12 +1,24 @@
use crate::{
activities::{verify_activity, verify_mod_action, verify_person_in_community},
objects::community::Group,
activities::{
community::announce::AnnouncableActivities,
generate_activity_id,
verify_activity,
verify_mod_action,
verify_person_in_community,
},
activity_queue::send_to_community_new,
extensions::context::lemmy_context,
objects::{community::Group, ToApub},
ActorType,
};
use activitystreams::activity::kind::UpdateType;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
use lemmy_db_queries::{ApubObject, Crud};
use lemmy_db_schema::source::community::{Community, CommunityForm};
use lemmy_db_schema::source::{
community::{Community, CommunityForm},
person::Person,
};
use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
use url::Url;
@ -25,6 +37,31 @@ pub struct UpdateCommunity {
common: ActivityCommonFields,
}
impl UpdateCommunity {
pub async fn send(
community: &Community,
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let id = generate_activity_id(UpdateType::Update)?;
let update = UpdateCommunity {
to: PublicUrl::Public,
object: community.to_apub(context.pool()).await?,
cc: [community.actor_id()],
kind: UpdateType::Update,
common: ActivityCommonFields {
context: lemmy_context(),
id: id.clone(),
actor: actor.actor_id(),
unparsed: Default::default(),
},
};
let activity = AnnouncableActivities::UpdateCommunity(Box::new(update));
send_to_community_new(activity, &id, actor, community, vec![], context).await
}
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UpdateCommunity {
async fn verify(

View file

@ -26,8 +26,8 @@ pub mod deletion;
pub mod following;
pub mod post;
pub mod private_message;
pub mod removal;
pub mod send;
pub mod undo_remove;
pub mod voting;
#[derive(Clone, Debug, ToString, Deserialize, Serialize)]

View file

@ -1,2 +0,0 @@
pub mod remove;
pub mod undo_remove;

View file

@ -1,38 +1,10 @@
use crate::{
activities::generate_activity_id,
activity_queue::{send_to_community, send_to_community_followers},
check_is_apub_id_valid,
extensions::context::lemmy_context,
fetcher::get_or_fetch_and_upsert_actor,
generate_moderators_url,
insert_activity,
objects::ToApub,
ActorType,
CommunityType,
};
use activitystreams::{
activity::{
kind::{AddType, AnnounceType, BlockType, RemoveType, UndoType, UpdateType},
Add,
Announce,
Block,
OptTargetRefExt,
Remove,
Undo,
Update,
},
base::{AnyBase, BaseExt, ExtendsExt},
object::ObjectExt,
public,
};
use anyhow::Context;
use crate::{check_is_apub_id_valid, ActorType, CommunityType};
use itertools::Itertools;
use lemmy_api_common::blocking;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::source::{community::Community, person::Person};
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use lemmy_utils::LemmyError;
use url::Url;
impl ActorType for Community {
@ -67,71 +39,6 @@ impl CommunityType for Community {
self.followers_url.clone().into()
}
/// If a remote community is updated by a local mod, send the updated info to the community's
/// instance.
async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
if self.local {
// Do nothing, other instances will automatically refetch the community
} else {
let mut update = Update::new(
mod_.actor_id(),
AnyBase::from_arbitrary_json(self.to_apub(context.pool()).await?)?,
);
update
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(UpdateType::Update)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()]);
send_to_community(update, &mod_, self, None, context).await?;
}
Ok(())
}
/// Wraps an activity sent to the community in an announce, and then sends the announce to all
/// community followers.
///
/// If we are announcing a local activity, it hasn't been stored in the database yet, and we need
/// to do it here, so that it can be fetched by ID. Remote activities are inserted into DB in the
/// inbox.
///
/// If the `object` of the announced activity is an actor, the actor ID needs to be passed as
/// `object_actor`, so that the announce can be delivered to that user.
async fn send_announce(
&self,
activity: AnyBase,
object_actor: Option<Url>,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let inner_id = activity.id().context(location_info!())?;
if inner_id.domain() == Some(&Settings::get().get_hostname_without_port()?) {
insert_activity(inner_id, activity.clone(), true, false, context.pool()).await?;
}
let mut ccs = vec![self.followers_url()];
let mut object_actor_inbox: Option<Url> = None;
if let Some(actor_id) = object_actor {
// Ignore errors, maybe its not actually an actor
// TODO: should pass the actual request counter in, but that seems complicated
let actor = get_or_fetch_and_upsert_actor(&actor_id, context, &mut 0)
.await
.ok();
if let Some(actor) = actor {
ccs.push(actor_id);
object_actor_inbox = Some(actor.get_shared_inbox_or_inbox_url());
}
}
let mut announce = Announce::new(self.actor_id(), activity);
announce
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(AnnounceType::Announce)?)
.set_to(public())
.set_many_ccs(ccs);
send_to_community_followers(announce, self, object_actor_inbox, context).await?;
Ok(())
}
/// For a given community, returns the inboxes of all followers.
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
let id = self.id;
@ -152,82 +59,4 @@ impl CommunityType for Community {
Ok(inboxes)
}
async fn send_add_mod(
&self,
actor: &Person,
added_mod: Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let mut add = Add::new(actor.actor_id(), added_mod.actor_id());
add
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(AddType::Add)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()])
.set_target(generate_moderators_url(&self.actor_id)?.into_inner());
send_to_community(add, actor, self, Some(added_mod.actor_id()), context).await?;
Ok(())
}
async fn send_remove_mod(
&self,
actor: &Person,
removed_mod: Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let mut remove = Remove::new(actor.actor_id(), removed_mod.actor_id());
remove
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(RemoveType::Remove)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()])
.set_target(generate_moderators_url(&self.actor_id)?.into_inner());
send_to_community(remove, actor, self, Some(removed_mod.actor_id()), context).await?;
Ok(())
}
async fn send_block_user(
&self,
actor: &Person,
blocked_user: Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let mut block = Block::new(actor.actor_id(), blocked_user.actor_id());
block
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(BlockType::Block)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()]);
send_to_community(block, actor, self, Some(blocked_user.actor_id()), context).await?;
Ok(())
}
async fn send_undo_block_user(
&self,
actor: &Person,
unblocked_user: Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
let mut block = Block::new(actor.actor_id(), unblocked_user.actor_id());
block
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(BlockType::Block)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()]);
// Undo that fake activity
let mut undo = Undo::new(actor.actor_id(), block.into_any_base()?);
undo
.set_many_contexts(lemmy_context())
.set_id(generate_activity_id(UndoType::Undo)?)
.set_to(public())
.set_many_ccs(vec![self.actor_id()]);
send_to_community(undo, actor, self, Some(unblocked_user.actor_id()), context).await?;
Ok(())
}
}

View file

@ -1,6 +1,6 @@
use crate::activities::{
community::remove_mod::RemoveMod,
deletion::{undo_delete::UndoDelete, verify_delete_activity},
removal::remove::RemoveMod,
verify_activity,
};
use activitystreams::activity::kind::UndoType;

View file

@ -1,16 +1,10 @@
use crate::{
activities::community::announce::{AnnouncableActivities, AnnounceActivity},
check_is_apub_id_valid,
extensions::signatures::sign_and_send,
insert_activity,
ActorType,
CommunityType,
APUB_JSON_CONTENT_TYPE,
};
use activitystreams::{
base::{BaseExt, Extends, ExtendsExt},
object::AsObject,
};
use anyhow::{anyhow, Context, Error};
use background_jobs::{
create_server,
@ -21,95 +15,15 @@ use background_jobs::{
QueueHandle,
WorkerConfig,
};
use itertools::Itertools;
use lemmy_db_schema::source::{community::Community, person::Person};
use lemmy_db_schema::source::community::Community;
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{debug, info, warn};
use log::{info, warn};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, env, fmt::Debug, future::Future, pin::Pin};
use url::Url;
/// From a local community, send activity to all remote followers.
///
/// * `activity` the apub activity to send
/// * `community` the sending community
/// * `extra_inbox` actor inbox which should receive the activity, in addition to followers
pub(crate) async fn send_to_community_followers<T, Kind>(
activity: T,
community: &Community,
extra_inbox: Option<Url>,
context: &LemmyContext,
) -> Result<(), LemmyError>
where
T: AsObject<Kind> + Extends<Kind> + Debug + BaseExt<Kind>,
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
let extra_inbox: Vec<Url> = extra_inbox.into_iter().collect();
let follower_inboxes: Vec<Url> = vec![
community.get_follower_inboxes(context.pool()).await?,
extra_inbox,
]
.iter()
.flatten()
.unique()
.filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname))
.filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
.map(|inbox| inbox.to_owned())
.collect();
debug!(
"Sending activity {:?} to followers of {}",
&activity.id_unchecked().map(ToString::to_string),
&community.actor_id
);
send_activity_internal(context, activity, community, follower_inboxes, true, false).await?;
Ok(())
}
/// Sends an activity from a local person to a remote community.
///
/// * `activity` the activity to send
/// * `creator` the creator of the activity
/// * `community` the destination community
/// * `object_actor` if the object of the activity is an actor, it should be passed here so it can
/// be sent directly to the actor
///
pub(crate) async fn send_to_community<T, Kind>(
activity: T,
creator: &Person,
community: &Community,
object_actor: Option<Url>,
context: &LemmyContext,
) -> Result<(), LemmyError>
where
T: AsObject<Kind> + Extends<Kind> + Debug + BaseExt<Kind>,
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
// if this is a local community, we need to do an announce from the community instead
if community.local {
community
.send_announce(activity.into_any_base()?, object_actor, context)
.await?;
} else {
let inbox = community.get_shared_inbox_or_inbox_url();
check_is_apub_id_valid(&inbox, false)?;
debug!(
"Sending activity {:?} to community {}",
&activity.id_unchecked().map(ToString::to_string),
&community.actor_id
);
// dont send to object_actor here, as that is responsibility of the community itself
send_activity_internal(context, activity, creator, vec![inbox], true, false).await?;
}
Ok(())
}
pub(crate) async fn send_to_community_new(
activity: AnnouncableActivities,
activity_id: &Url,
@ -184,62 +98,6 @@ where
Ok(())
}
/// Create new `SendActivityTasks`, which will deliver the given activity to inboxes, as well as
/// handling signing and retrying failed deliveres.
///
/// The caller of this function needs to remove any blocked domains from `to`,
/// using `check_is_apub_id_valid()`.
async fn send_activity_internal<T, Kind>(
context: &LemmyContext,
activity: T,
actor: &dyn ActorType,
inboxes: Vec<Url>,
insert_into_db: bool,
sensitive: bool,
) -> Result<(), LemmyError>
where
T: AsObject<Kind> + Extends<Kind> + Debug,
Kind: Serialize,
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
{
if !Settings::get().federation.enabled || inboxes.is_empty() {
return Ok(());
}
// Don't send anything to ourselves
let hostname = Settings::get().get_hostname_without_port()?;
let inboxes: Vec<&Url> = inboxes
.iter()
.filter(|i| i.domain().expect("valid inbox url") != hostname)
.collect();
let activity = activity.into_any_base()?;
let serialised_activity = serde_json::to_string(&activity)?;
// This is necessary because send_comment and send_comment_mentions
// might send the same ap_id
if insert_into_db {
let id = activity.id().context(location_info!())?;
insert_activity(id, activity.clone(), true, sensitive, context.pool()).await?;
}
for i in inboxes {
let message = SendActivityTask {
activity: serialised_activity.to_owned(),
inbox: i.to_owned(),
actor_id: actor.actor_id(),
private_key: actor.private_key().context(location_info!())?,
};
if env::var("LEMMY_TEST_SEND_SYNC").is_ok() {
do_send(message, &Client::default()).await?;
} else {
context.activity_queue.queue::<SendActivityTask>(message)?;
}
}
Ok(())
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct SendActivityTask {
activity: String,

View file

@ -4,6 +4,7 @@ use crate::activities::{
add_mod::AddMod,
announce::AnnounceActivity,
block_user::BlockUserFromCommunity,
remove_mod::RemoveMod,
undo_block_user::UndoBlockUserFromCommunity,
update::UpdateCommunity,
},
@ -15,7 +16,7 @@ use crate::activities::{
delete::DeletePrivateMessage,
undo_delete::UndoDeletePrivateMessage,
},
removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
undo_remove::UndoRemovePostCommentOrCommunity,
voting::{undo_vote::UndoVote, vote::Vote},
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};

View file

@ -10,7 +10,6 @@ pub mod migrations;
pub mod objects;
use crate::extensions::signatures::PublicKey;
use activitystreams::base::AnyBase;
use anyhow::{anyhow, Context};
use diesel::NotFound;
use lemmy_api_common::blocking;
@ -139,41 +138,6 @@ trait ActorType {
pub trait CommunityType {
fn followers_url(&self) -> Url;
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
async fn send_announce(
&self,
activity: AnyBase,
object: Option<Url>,
context: &LemmyContext,
) -> Result<(), LemmyError>;
async fn send_add_mod(
&self,
actor: &Person,
added_mod: Person,
context: &LemmyContext,
) -> Result<(), LemmyError>;
async fn send_remove_mod(
&self,
actor: &Person,
removed_mod: Person,
context: &LemmyContext,
) -> Result<(), LemmyError>;
async fn send_block_user(
&self,
actor: &Person,
blocked_user: Person,
context: &LemmyContext,
) -> Result<(), LemmyError>;
async fn send_undo_block_user(
&self,
actor: &Person,
blocked_user: Person,
context: &LemmyContext,
) -> Result<(), LemmyError>;
}
pub enum EndpointType {

View file

@ -53,13 +53,6 @@ pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), LemmyError> {
Ok(())
}
pub fn verify_domains_match_opt(a: &Url, b: Option<&Url>) -> Result<(), LemmyError> {
if let Some(b2) = b {
return verify_domains_match(a, b2);
}
Ok(())
}
pub fn verify_urls_match(a: &Url, b: &Url) -> Result<(), LemmyError> {
if a != b {
return Err(DomainError.into());