mirror of https://github.com/LemmyNet/lemmy.git
Send Announce/Page, Announce/Note for Pleroma compatibility
parent
3a90f462fa
commit
f129cd51b8
|
@ -26,13 +26,12 @@ pub(crate) trait GetCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnnounceActivity {
|
impl AnnounceActivity {
|
||||||
pub async fn send(
|
fn new(
|
||||||
object: AnnouncableActivities,
|
object: AnnouncableActivities,
|
||||||
community: &ApubCommunity,
|
community: &ApubCommunity,
|
||||||
additional_inboxes: Vec<Url>,
|
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<AnnounceActivity, LemmyError> {
|
||||||
let announce = AnnounceActivity {
|
Ok(AnnounceActivity {
|
||||||
actor: ObjectId::new(community.actor_id()),
|
actor: ObjectId::new(community.actor_id()),
|
||||||
to: vec![public()],
|
to: vec![public()],
|
||||||
object,
|
object,
|
||||||
|
@ -43,11 +42,49 @@ impl AnnounceActivity {
|
||||||
&context.settings().get_protocol_and_hostname(),
|
&context.settings().get_protocol_and_hostname(),
|
||||||
)?,
|
)?,
|
||||||
unparsed: Default::default(),
|
unparsed: Default::default(),
|
||||||
};
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send(
|
||||||
|
object: AnnouncableActivities,
|
||||||
|
community: &ApubCommunity,
|
||||||
|
additional_inboxes: Vec<Url>,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let announce = AnnounceActivity::new(object.clone(), community, context)?;
|
||||||
let inboxes = community
|
let inboxes = community
|
||||||
.get_follower_inboxes(additional_inboxes, context)
|
.get_follower_inboxes(additional_inboxes.clone(), context)
|
||||||
.await?;
|
.await?;
|
||||||
send_lemmy_activity(context, &announce, &announce.id, community, inboxes, false).await
|
send_lemmy_activity(
|
||||||
|
context,
|
||||||
|
&announce,
|
||||||
|
&announce.id,
|
||||||
|
community,
|
||||||
|
inboxes.clone(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Pleroma (and likely Mastodon) can't handle activities like Announce/Create/Page, so for
|
||||||
|
// compatibility, we also send Announce/Page and Announce/Note (for new and updated
|
||||||
|
// posts/comments).
|
||||||
|
use AnnouncableActivities::*;
|
||||||
|
let object = match object {
|
||||||
|
CreateOrUpdatePost(c) => Page(c.object),
|
||||||
|
CreateOrUpdateComment(c) => Note(c.object),
|
||||||
|
_ => return Ok(()),
|
||||||
|
};
|
||||||
|
let announce_compat = AnnounceActivity::new(object, community, context)?;
|
||||||
|
send_lemmy_activity(
|
||||||
|
context,
|
||||||
|
&announce_compat,
|
||||||
|
&announce_compat.id,
|
||||||
|
community,
|
||||||
|
inboxes,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +114,7 @@ impl ActivityHandler for AnnounceActivity {
|
||||||
if is_activity_already_known(context.pool(), &object_data.id).await? {
|
if is_activity_already_known(context.pool(), &object_data.id).await? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
insert_activity(
|
insert_activity(&object_data.id, &self.object, false, true, context.pool()).await?;
|
||||||
&object_data.id,
|
|
||||||
self.object.clone(),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
context.pool(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
self.object.receive(context, request_counter).await
|
self.object.receive(context, request_counter).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub(crate) async fn send_to_community<T: ActorType>(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
// if this is a local community, we need to do an announce from the community instead
|
// if this is a local community, we need to do an announce from the community instead
|
||||||
if community.local {
|
if community.local {
|
||||||
insert_activity(activity_id, activity.clone(), true, false, context.pool()).await?;
|
insert_activity(activity_id, &activity, true, false, context.pool()).await?;
|
||||||
AnnounceActivity::send(activity, community, additional_inboxes, context).await?;
|
AnnounceActivity::send(activity, community, additional_inboxes, context).await?;
|
||||||
} else {
|
} else {
|
||||||
let mut inboxes = additional_inboxes;
|
let mut inboxes = additional_inboxes;
|
||||||
|
|
|
@ -173,7 +173,7 @@ async fn send_lemmy_activity<T: Serialize>(
|
||||||
|
|
||||||
insert_activity(
|
insert_activity(
|
||||||
activity_id,
|
activity_id,
|
||||||
serialised_activity.clone(),
|
&serialised_activity,
|
||||||
true,
|
true,
|
||||||
sensitive,
|
sensitive,
|
||||||
context.pool(),
|
context.pool(),
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl CreateOrUpdatePost {
|
||||||
})
|
})
|
||||||
.await??
|
.await??
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let create_or_update = CreateOrUpdatePost::new(post, actor, &community, kind, context).await?;
|
let create_or_update = CreateOrUpdatePost::new(post, actor, &community, kind, context).await?;
|
||||||
let id = create_or_update.id.clone();
|
let id = create_or_update.id.clone();
|
||||||
let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
|
let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
|
||||||
|
|
|
@ -1,29 +1,32 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::community::announce::GetCommunity,
|
activities::community::announce::GetCommunity,
|
||||||
objects::community::ApubCommunity,
|
objects::community::ApubCommunity,
|
||||||
protocol::activities::{
|
protocol::{
|
||||||
community::{
|
activities::{
|
||||||
add_mod::AddMod,
|
community::{
|
||||||
announce::AnnounceActivity,
|
add_mod::AddMod,
|
||||||
block_user::BlockUserFromCommunity,
|
announce::AnnounceActivity,
|
||||||
remove_mod::RemoveMod,
|
block_user::BlockUserFromCommunity,
|
||||||
report::Report,
|
remove_mod::RemoveMod,
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
report::Report,
|
||||||
update::UpdateCommunity,
|
undo_block_user::UndoBlockUserFromCommunity,
|
||||||
|
update::UpdateCommunity,
|
||||||
|
},
|
||||||
|
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
||||||
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
|
following::{
|
||||||
|
accept::AcceptFollowCommunity,
|
||||||
|
follow::FollowCommunity,
|
||||||
|
undo_follow::UndoFollowCommunity,
|
||||||
|
},
|
||||||
|
private_message::{
|
||||||
|
create_or_update::CreateOrUpdatePrivateMessage,
|
||||||
|
delete::DeletePrivateMessage,
|
||||||
|
undo_delete::UndoDeletePrivateMessage,
|
||||||
|
},
|
||||||
|
voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
},
|
},
|
||||||
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
objects::{note::Note, page::Page},
|
||||||
deletion::{delete::Delete, undo_delete::UndoDelete},
|
|
||||||
following::{
|
|
||||||
accept::AcceptFollowCommunity,
|
|
||||||
follow::FollowCommunity,
|
|
||||||
undo_follow::UndoFollowCommunity,
|
|
||||||
},
|
|
||||||
private_message::{
|
|
||||||
create_or_update::CreateOrUpdatePrivateMessage,
|
|
||||||
delete::DeletePrivateMessage,
|
|
||||||
undo_delete::UndoDeletePrivateMessage,
|
|
||||||
},
|
|
||||||
voting::{undo_vote::UndoVote, vote::Vote},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_apub_lib::traits::ActivityHandler;
|
use lemmy_apub_lib::traits::ActivityHandler;
|
||||||
|
@ -79,6 +82,10 @@ pub enum AnnouncableActivities {
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
||||||
AddMod(AddMod),
|
AddMod(AddMod),
|
||||||
RemoveMod(RemoveMod),
|
RemoveMod(RemoveMod),
|
||||||
|
// For compatibility with Pleroma/Mastodon (send only)
|
||||||
|
Page(Page),
|
||||||
|
// For compatibility with Pleroma/Mastodon (send only)
|
||||||
|
Note(Note),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -101,6 +108,8 @@ impl GetCommunity for AnnouncableActivities {
|
||||||
UndoBlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
|
UndoBlockUserFromCommunity(a) => a.get_community(context, request_counter).await?,
|
||||||
AddMod(a) => a.get_community(context, request_counter).await?,
|
AddMod(a) => a.get_community(context, request_counter).await?,
|
||||||
RemoveMod(a) => a.get_community(context, request_counter).await?,
|
RemoveMod(a) => a.get_community(context, request_counter).await?,
|
||||||
|
Page(a) => a.get_community(context, request_counter).await?,
|
||||||
|
Note(a) => a.get_community(context, request_counter).await?,
|
||||||
};
|
};
|
||||||
Ok(community)
|
Ok(community)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub(in crate::http) async fn receive_group_inbox(
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let actor_id = ObjectId::new(activity_data.actor.clone());
|
let actor_id = ObjectId::new(activity_data.actor.clone());
|
||||||
let res = receive_activity(request, activity.clone(), activity_data, context).await;
|
let res = receive_activity(request, activity.clone(), activity_data, context).await?;
|
||||||
|
|
||||||
if let GroupInboxActivities::AnnouncableActivities(announcable) = activity {
|
if let GroupInboxActivities::AnnouncableActivities(announcable) = activity {
|
||||||
let community = announcable.get_community(context, &mut 0).await?;
|
let community = announcable.get_community(context, &mut 0).await?;
|
||||||
|
@ -89,7 +89,7 @@ pub(in crate::http) async fn receive_group_inbox(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an empty followers collection, only populating the size (for privacy).
|
/// Returns an empty followers collection, only populating the size (for privacy).
|
||||||
|
|
|
@ -109,14 +109,7 @@ where
|
||||||
|
|
||||||
// Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen
|
// Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen
|
||||||
// if we receive the same activity twice in very quick succession.
|
// if we receive the same activity twice in very quick succession.
|
||||||
insert_activity(
|
insert_activity(&activity_data.id, &activity, false, true, context.pool()).await?;
|
||||||
&activity_data.id,
|
|
||||||
activity.clone(),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
context.pool(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!("Receiving activity {}", activity_data.id.to_string());
|
info!("Receiving activity {}", activity_data.id.to_string());
|
||||||
activity
|
activity
|
||||||
|
|
|
@ -179,7 +179,7 @@ pub async fn get_actor_id_from_name(
|
||||||
/// persistent.
|
/// persistent.
|
||||||
async fn insert_activity<T>(
|
async fn insert_activity<T>(
|
||||||
ap_id: &Url,
|
ap_id: &Url,
|
||||||
activity: T,
|
activity: &T,
|
||||||
local: bool,
|
local: bool,
|
||||||
sensitive: bool,
|
sensitive: bool,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
|
@ -187,9 +187,10 @@ async fn insert_activity<T>(
|
||||||
where
|
where
|
||||||
T: Serialize + std::fmt::Debug + Send + 'static,
|
T: Serialize + std::fmt::Debug + Send + 'static,
|
||||||
{
|
{
|
||||||
|
let data = serde_json::to_value(activity)?;
|
||||||
let ap_id = ap_id.to_owned().into();
|
let ap_id = ap_id.to_owned().into();
|
||||||
blocking(pool, move |conn| {
|
blocking(pool, move |conn| {
|
||||||
Activity::insert(conn, ap_id, &activity, local, sensitive)
|
Activity::insert(conn, ap_id, data, local, sensitive)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
activities::community::announce::GetCommunity,
|
||||||
fetcher::post_or_comment::PostOrComment,
|
fetcher::post_or_comment::PostOrComment,
|
||||||
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
|
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||||
protocol::Source,
|
protocol::Source,
|
||||||
};
|
};
|
||||||
use activitystreams::{object::kind::NoteType, unparsed::Unparsed};
|
use activitystreams::{object::kind::NoteType, unparsed::Unparsed};
|
||||||
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
|
use lemmy_apub_lib::{
|
||||||
use lemmy_db_schema::{newtypes::CommentId, source::post::Post, traits::Crud};
|
data::Data,
|
||||||
|
object_id::ObjectId,
|
||||||
|
traits::ActivityHandler,
|
||||||
|
values::MediaTypeHtml,
|
||||||
|
};
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
newtypes::CommentId,
|
||||||
|
source::{community::Community, post::Post},
|
||||||
|
traits::Crud,
|
||||||
|
};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -81,3 +92,33 @@ impl Note {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For Pleroma/Mastodon compat. Unimplemented because its only used for sending.
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl ActivityHandler for Note {
|
||||||
|
type DataType = LemmyContext;
|
||||||
|
async fn verify(&self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> {
|
||||||
|
Err(anyhow!("Announce/Page can only be sent, not received").into())
|
||||||
|
}
|
||||||
|
async fn receive(self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl GetCommunity for Note {
|
||||||
|
async fn get_community(
|
||||||
|
&self,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<ApubCommunity, LemmyError> {
|
||||||
|
let post = self.get_parents(context, request_counter).await?.0;
|
||||||
|
Ok(
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
Community::read(conn, post.community_id)
|
||||||
|
})
|
||||||
|
.await??
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
activities::community::announce::GetCommunity,
|
||||||
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||||
protocol::{ImageObject, Source},
|
protocol::{ImageObject, Source},
|
||||||
};
|
};
|
||||||
use activitystreams::{object::kind::PageType, unparsed::Unparsed};
|
use activitystreams::{object::kind::PageType, unparsed::Unparsed};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
|
use lemmy_apub_lib::{
|
||||||
|
data::Data,
|
||||||
|
object_id::ObjectId,
|
||||||
|
traits::ActivityHandler,
|
||||||
|
values::MediaTypeHtml,
|
||||||
|
};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -73,3 +79,26 @@ impl Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For Pleroma/Mastodon compat. Unimplemented because its only used for sending.
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl ActivityHandler for Page {
|
||||||
|
type DataType = LemmyContext;
|
||||||
|
async fn verify(&self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> {
|
||||||
|
Err(anyhow!("Announce/Page can only be sent, not received").into())
|
||||||
|
}
|
||||||
|
async fn receive(self, _: &Data<Self::DataType>, _: &mut i32) -> Result<(), LemmyError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl GetCommunity for Page {
|
||||||
|
async fn get_community(
|
||||||
|
&self,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<ApubCommunity, LemmyError> {
|
||||||
|
self.extract_community(context, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::{newtypes::DbUrl, source::activity::*, traits::Crud};
|
use crate::{newtypes::DbUrl, source::activity::*, traits::Crud};
|
||||||
use diesel::{dsl::*, result::Error, *};
|
use diesel::{dsl::*, result::Error, *};
|
||||||
use serde::Serialize;
|
use serde_json::Value;
|
||||||
use std::{
|
use std::io::{Error as IoError, ErrorKind};
|
||||||
fmt::Debug,
|
|
||||||
io::{Error as IoError, ErrorKind},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Crud for Activity {
|
impl Crud for Activity {
|
||||||
type Form = ActivityForm;
|
type Form = ActivityForm;
|
||||||
|
@ -38,19 +35,16 @@ impl Crud for Activity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Activity {
|
impl Activity {
|
||||||
pub fn insert<T>(
|
pub fn insert(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
ap_id: DbUrl,
|
ap_id: DbUrl,
|
||||||
data: &T,
|
data: Value,
|
||||||
local: bool,
|
local: bool,
|
||||||
sensitive: bool,
|
sensitive: bool,
|
||||||
) -> Result<Activity, IoError>
|
) -> Result<Activity, IoError> {
|
||||||
where
|
|
||||||
T: Serialize + Debug,
|
|
||||||
{
|
|
||||||
let activity_form = ActivityForm {
|
let activity_form = ActivityForm {
|
||||||
ap_id,
|
ap_id,
|
||||||
data: serde_json::to_value(&data)?,
|
data,
|
||||||
local: Some(local),
|
local: Some(local),
|
||||||
sensitive,
|
sensitive,
|
||||||
updated: None,
|
updated: None,
|
||||||
|
|
Loading…
Reference in New Issue