{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "comments_enabled": {
- "id": "pt:commentsEnabled",
- "type": "sc:Boolean"
- },
- "matrixUserId": {
- "id": "as:alsoKnownAs",
- "type": "sc:Text"
- },
- "moderators": "as:moderators",
- "pt": "https://join-lemmy.org#",
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied"
- },
- "https://w3id.org/security/v1"
- ],
"id": "https://enterprise.lemmy.ml/comment/38741",
"type": "Note",
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "comments_enabled": {
- "id": "pt:commentsEnabled",
- "type": "sc:Boolean"
- },
- "matrixUserId": {
- "id": "as:alsoKnownAs",
- "type": "sc:Text"
- },
- "moderators": "as:moderators",
- "pt": "https://join-lemmy.org#",
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied"
- },
- "https://w3id.org/security/v1"
- ],
"id": "https://enterprise.lemmy.ml/c/tenforward",
"type": "Group",
"preferredUsername": "main",
{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "comments_enabled": {
- "id": "pt:commentsEnabled",
- "type": "sc:Boolean"
- },
- "matrixUserId": {
- "id": "as:alsoKnownAs",
- "type": "sc:Text"
- },
- "moderators": "as:moderators",
- "pt": "https://join-lemmy.org#",
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied"
- },
- "https://w3id.org/security/v1"
- ],
"id": "https://enterprise.lemmy.ml/u/picard",
"type": "Person",
"preferredUsername": "picard",
{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "comments_enabled": {
- "id": "pt:commentsEnabled",
- "type": "sc:Boolean"
- },
- "matrixUserId": {
- "id": "as:alsoKnownAs",
- "type": "sc:Text"
- },
- "moderators": "as:moderators",
- "pt": "https://join-lemmy.org#",
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied"
- },
- "https://w3id.org/security/v1"
- ],
"id": "https://enterprise.lemmy.ml/post/55143",
"type": "Page",
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- {
- "comments_enabled": {
- "id": "pt:commentsEnabled",
- "type": "sc:Boolean"
- },
- "matrixUserId": {
- "id": "as:alsoKnownAs",
- "type": "sc:Text"
- },
- "moderators": "as:moderators",
- "pt": "https://join-lemmy.org#",
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied"
- },
- "https://w3id.org/security/v1"
- ],
"id": "https://enterprise.lemmy.ml/private_message/1621",
"type": "ChatMessage",
"attributedTo": "https://enterprise.lemmy.ml/u/picard",
verify_person_in_community,
CreateOrUpdateType,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{
comment::{ApubComment, Note},
person::ApubPerson,
},
};
-use activitystreams::{
- base::AnyBase,
- link::Mention,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{link::Mention, public, unparsed::Unparsed};
use lemmy_api_common::{blocking, check_post_deleted_or_removed};
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: CreateOrUpdateType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
tag: maa.tags,
kind,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
verify_mod_action,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
generate_moderators_url,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::AddType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::AddType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: AddType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: AddType::Add,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
deletion::{delete::Delete, undo_delete::UndoDelete},
generate_activity_id,
post::create_or_update::CreateOrUpdatePost,
+ send_lemmy_activity,
verify_activity,
verify_is_public,
voting::{undo_vote::UndoVote, vote::Vote},
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
http::is_activity_already_known,
insert_activity,
objects::community::ApubCommunity,
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::AnnounceType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::AnnounceType, public, unparsed::Unparsed};
use lemmy_apub_lib::{
data::Data,
traits::{ActivityFields, ActivityHandler, ActorType},
#[serde(rename = "type")]
kind: AnnounceType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
&AnnounceType::Announce,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
};
let inboxes = list_community_follower_inboxes(community, additional_inboxes, context).await?;
verify_mod_action,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::BlockType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::BlockType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: BlockType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
BlockType::Block,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
})
}
use crate::{
- activities::community::announce::{AnnouncableActivities, AnnounceActivity},
+ activities::{
+ community::announce::{AnnouncableActivities, AnnounceActivity},
+ send_lemmy_activity,
+ },
check_is_apub_id_valid,
fetcher::object_id::ObjectId,
insert_activity,
objects::community::ApubCommunity,
- send_lemmy_activity,
};
use itertools::Itertools;
use lemmy_apub_lib::traits::ActorType;
verify_mod_action,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
generate_moderators_url,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::RemoveType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::RemoveType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
kind: RemoveType,
pub(in crate::activities) target: Url,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
object: ObjectId::new(removed_mod.actor_id()),
target: generate_moderators_url(&community.actor_id)?.into(),
id: id.clone(),
- context: lemmy_context(),
cc: vec![community.actor_id()],
kind: RemoveType::Remove,
unparsed: Default::default(),
verify_mod_action,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::UndoType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::UndoType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: UndoType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: UndoType::Undo,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
verify_mod_action,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{
community::{ApubCommunity, Group},
person::ApubPerson,
},
};
-use activitystreams::{
- activity::kind::UpdateType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::UpdateType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: UpdateType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: UpdateType::Update,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
verify_activity,
verify_is_public,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::DeleteType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::DeleteType, public, unparsed::Unparsed};
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
/// deleting their own content.
pub(in crate::activities::deletion) summary: Option<String>,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
DeleteType::Delete,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
})
}
verify_activity,
verify_is_public,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
};
-use activitystreams::{
- activity::kind::UndoType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::UndoType, public, unparsed::Unparsed};
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[serde(rename = "type")]
kind: UndoType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: UndoType::Undo,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
use crate::{
- activities::{following::follow::FollowCommunity, generate_activity_id, verify_activity},
- context::lemmy_context,
+ activities::{
+ following::follow::FollowCommunity,
+ generate_activity_id,
+ send_lemmy_activity,
+ verify_activity,
+ },
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::AcceptType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::AcceptType, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: AcceptType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
AcceptType::Accept,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
};
let inbox = vec![person.inbox_url()];
activities::{
following::accept::AcceptFollowCommunity,
generate_activity_id,
+ send_lemmy_activity,
verify_activity,
verify_person,
verify_person_in_community,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::FollowType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::FollowType, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: FollowType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
FollowType::Follow,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
})
}
activities::{
following::follow::FollowCommunity,
generate_activity_id,
+ send_lemmy_activity,
verify_activity,
verify_person,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::UndoType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: UndoType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
UndoType::Undo,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
};
let inbox = vec![community.shared_inbox_or_inbox_url()];
use crate::{
check_is_apub_id_valid,
+ context::WithContext,
fetcher::object_id::ObjectId,
generate_moderators_url,
+ insert_activity,
objects::{community::ApubCommunity, person::ApubPerson},
};
use activitystreams::public;
use anyhow::anyhow;
use lemmy_api_common::blocking;
-use lemmy_apub_lib::{traits::ActivityFields, verify::verify_domains_match};
+use lemmy_apub_lib::{
+ activity_queue::send_activity,
+ traits::{ActivityFields, ActorType},
+ verify::verify_domains_match,
+};
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::{
community_person_ban_view::CommunityPersonBanView,
};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
+use log::info;
use serde::{Deserialize, Serialize};
use strum_macros::ToString;
use url::{ParseError, Url};
);
Url::parse(&id)
}
+
+async fn send_lemmy_activity<T: Serialize>(
+ context: &LemmyContext,
+ activity: &T,
+ activity_id: &Url,
+ actor: &dyn ActorType,
+ inboxes: Vec<Url>,
+ sensitive: bool,
+) -> Result<(), LemmyError> {
+ if !context.settings().federation.enabled || inboxes.is_empty() {
+ return Ok(());
+ }
+ let activity = WithContext::new(activity);
+
+ info!("Sending activity {}", activity_id.to_string());
+
+ // Don't send anything to ourselves
+ // TODO: this should be a debug assert
+ let hostname = context.settings().get_hostname_without_port()?;
+ let inboxes: Vec<&Url> = inboxes
+ .iter()
+ .filter(|i| i.domain().expect("valid inbox url") != hostname)
+ .collect();
+
+ let serialised_activity = serde_json::to_string(&activity)?;
+
+ insert_activity(
+ activity_id,
+ serialised_activity.clone(),
+ true,
+ sensitive,
+ context.pool(),
+ )
+ .await?;
+
+ send_activity(
+ serialised_activity,
+ actor,
+ inboxes,
+ context.client(),
+ context.activity_queue(),
+ )
+ .await
+}
verify_person_in_community,
CreateOrUpdateType,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{
community::ApubCommunity,
post::{ApubPost, Page},
},
};
-use activitystreams::{base::AnyBase, primitives::OneOrMany, public, unparsed::Unparsed};
+use activitystreams::{public, unparsed::Unparsed};
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[serde(rename = "type")]
kind: CreateOrUpdateType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
})
}
use crate::{
- activities::{generate_activity_id, verify_activity, verify_person, CreateOrUpdateType},
- context::lemmy_context,
+ activities::{
+ generate_activity_id,
+ send_lemmy_activity,
+ verify_activity,
+ verify_person,
+ CreateOrUpdateType,
+ },
fetcher::object_id::ObjectId,
objects::{
person::ApubPerson,
private_message::{ApubPrivateMessage, ChatMessage},
},
- send_lemmy_activity,
};
-use activitystreams::{base::AnyBase, primitives::OneOrMany, unparsed::Unparsed};
+use activitystreams::unparsed::Unparsed;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrUpdatePrivateMessage {
- #[serde(rename = "@context")]
- pub context: OneOrMany<AnyBase>,
id: Url,
actor: ObjectId<ApubPerson>,
to: [ObjectId<ApubPerson>; 1],
&context.settings().get_protocol_and_hostname(),
)?;
let create_or_update = CreateOrUpdatePrivateMessage {
- context: lemmy_context(),
id: id.clone(),
actor: ObjectId::new(actor.actor_id()),
to: [ObjectId::new(recipient.actor_id())],
use crate::{
- activities::{generate_activity_id, verify_activity, verify_person},
- context::lemmy_context,
+ activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person},
fetcher::object_id::ObjectId,
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::DeleteType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::DeleteType, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: DeleteType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
DeleteType::Delete,
&context.settings().get_protocol_and_hostname(),
)?,
- context: lemmy_context(),
unparsed: Default::default(),
})
}
activities::{
generate_activity_id,
private_message::delete::DeletePrivateMessage,
+ send_lemmy_activity,
verify_activity,
verify_person,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
- send_lemmy_activity,
-};
-use activitystreams::{
- activity::kind::UndoType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
};
+use activitystreams::{activity::kind::UndoType, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: UndoType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
object,
kind: UndoType::Undo,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
let inbox = vec![recipient.shared_inbox_or_inbox_url()];
use crate::{
- activities::{generate_activity_id, verify_activity, verify_person_in_community},
- context::lemmy_context,
+ activities::{
+ generate_activity_id,
+ send_lemmy_activity,
+ verify_activity,
+ verify_person_in_community,
+ },
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
- send_lemmy_activity,
PostOrComment,
};
-use activitystreams::{
- activity::kind::FlagType,
- base::AnyBase,
- primitives::OneOrMany,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::FlagType, unparsed::Unparsed};
use lemmy_api_common::{blocking, comment::CommentReportResponse, post::PostReportResponse};
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: FlagType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
summary: reason,
kind,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
send_lemmy_activity(
vote::{Vote, VoteType},
},
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
PostOrComment,
};
-use activitystreams::{
- activity::kind::UndoType,
- base::AnyBase,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{activity::kind::UndoType, public, unparsed::Unparsed};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
#[serde(rename = "type")]
kind: UndoType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: UndoType::Undo,
id: id.clone(),
- context: lemmy_context(),
unparsed: Default::default(),
};
let activity = AnnouncableActivities::UndoVote(undo_vote);
verify_person_in_community,
voting::{vote_comment, vote_post},
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{community::ApubCommunity, person::ApubPerson},
PostOrComment,
};
-use activitystreams::{base::AnyBase, primitives::OneOrMany, public, unparsed::Unparsed};
+use activitystreams::{public, unparsed::Unparsed};
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[serde(rename = "type")]
pub(in crate::activities::voting) kind: VoteType,
id: Url,
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(flatten)]
unparsed: Unparsed,
}
cc: vec![community.actor_id()],
kind: kind.clone(),
id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
- context: lemmy_context(),
unparsed: Default::default(),
})
}
use crate::{
collections::CommunityContext,
- context::lemmy_context,
fetcher::object_id::ObjectId,
generate_moderators_url,
objects::person::ApubPerson,
};
-use activitystreams::{
- base::AnyBase,
- chrono::NaiveDateTime,
- collection::kind::OrderedCollectionType,
- primitives::OneOrMany,
- url::Url,
-};
+use activitystreams::{chrono::NaiveDateTime, collection::kind::OrderedCollectionType};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{traits::ApubObject, verify::verify_domains_match};
use lemmy_db_schema::{
use lemmy_utils::LemmyError;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
+use url::Url;
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GroupModerators {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
r#type: OrderedCollectionType,
id: Url,
ordered_items: Vec<ObjectId<ApubPerson>>,
.map(|m| ObjectId::<ApubPerson>::new(m.moderator.actor_id.clone().into_inner()))
.collect();
Ok(GroupModerators {
- context: lemmy_context(),
r#type: OrderedCollectionType::OrderedCollection,
id: generate_moderators_url(&data.0.actor_id)?.into(),
ordered_items,
use crate::{
activities::{post::create_or_update::CreateOrUpdatePost, CreateOrUpdateType},
collections::CommunityContext,
- context::lemmy_context,
generate_outbox_url,
objects::{person::ApubPerson, post::ApubPost},
};
-use activitystreams::{
- base::AnyBase,
- chrono::NaiveDateTime,
- collection::kind::OrderedCollectionType,
- primitives::OneOrMany,
- url::Url,
-};
+use activitystreams::collection::kind::OrderedCollectionType;
+use chrono::NaiveDateTime;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
data::Data,
use lemmy_utils::LemmyError;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
+use url::Url;
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GroupOutbox {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
r#type: OrderedCollectionType,
id: Url,
ordered_items: Vec<CreateOrUpdatePost>,
}
Ok(GroupOutbox {
- context: lemmy_context(),
r#type: OrderedCollectionType::OrderedCollection,
id: generate_outbox_url(&data.0.actor_id)?.into(),
ordered_items,
use activitystreams::{base::AnyBase, context, primitives::OneOrMany};
+use serde::{Deserialize, Serialize};
use serde_json::json;
use url::Url;
-pub(crate) fn lemmy_context() -> OneOrMany<AnyBase> {
- let context_ext = AnyBase::from_arbitrary_json(json!(
- {
- "sc": "http://schema.org#",
- "sensitive": "as:sensitive",
- "stickied": "as:stickied",
- "pt": "https://join-lemmy.org#",
- "comments_enabled": {
- "type": "sc:Boolean",
- "id": "pt:commentsEnabled"
- },
- "moderators": "as:moderators",
- "matrixUserId": {
- "type": "sc:Text",
- "id": "as:alsoKnownAs"
- },
- }))
- .expect("parse context");
- OneOrMany::from(vec![
- AnyBase::from(context()),
- context_ext,
- AnyBase::from(Url::parse("https://w3id.org/security/v1").expect("parse context")),
- ])
+lazy_static! {
+ static ref CONTEXT: OneOrMany<AnyBase> = {
+ let context_ext = AnyBase::from_arbitrary_json(json!(
+ {
+ "sc": "http://schema.org#",
+ "sensitive": "as:sensitive",
+ "stickied": "as:stickied",
+ "pt": "https://join-lemmy.org#",
+ "comments_enabled": {
+ "type": "sc:Boolean",
+ "id": "pt:commentsEnabled"
+ },
+ "moderators": "as:moderators",
+ "matrixUserId": {
+ "type": "sc:Text",
+ "id": "as:alsoKnownAs"
+ },
+ }))
+ .expect("parse context");
+ OneOrMany::from(vec![
+ AnyBase::from(context()),
+ context_ext,
+ AnyBase::from(Url::parse("https://w3id.org/security/v1").expect("parse context")),
+ ])
+ };
+}
+
+#[derive(Serialize, Deserialize)]
+pub(crate) struct WithContext<T> {
+ #[serde(rename = "@context")]
+ context: OneOrMany<AnyBase>,
+ #[serde(flatten)]
+ inner: T,
+}
+
+impl<T> WithContext<T> {
+ pub(crate) fn new(inner: T) -> WithContext<T> {
+ WithContext {
+ context: CONTEXT.clone(),
+ inner,
+ }
+ }
+ pub(crate) fn inner(self) -> T {
+ self.inner
+ }
}
/// fetch through the search). This should be configurable.
static REQUEST_LIMIT: i32 = 25;
-// TODO: after moving this file to library, remove lazy_static dependency from apub crate
lazy_static! {
static ref CLIENT: Client = Client::builder()
.user_agent(build_user_agent(&Settings::get()))
comment::{ApubComment, Note},
post::{ApubPost, Page},
};
-use activitystreams::chrono::NaiveDateTime;
+use chrono::NaiveDateTime;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::source::{comment::CommentForm, post::PostForm};
use lemmy_utils::LemmyError;
post::{ApubPost, Page},
},
};
-use activitystreams::chrono::NaiveDateTime;
use anyhow::anyhow;
+use chrono::NaiveDateTime;
use itertools::Itertools;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
community_outbox::ApubCommunityOutbox,
CommunityContext,
},
- context::lemmy_context,
+ context::WithContext,
fetcher::object_id::ObjectId,
generate_outbox_url,
http::{
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received community inbox activity {}", unparsed);
- let activity = serde_json::from_str::<GroupInboxActivities>(&unparsed)?;
+ let activity = serde_json::from_str::<WithContext<GroupInboxActivities>>(&unparsed)?;
- receive_group_inbox(activity.clone(), request, &context).await?;
+ receive_group_inbox(activity.inner(), request, &context).await?;
Ok(HttpResponse::Ok().finish())
}
let mut collection = UnorderedCollection::new();
collection
- .set_many_contexts(lemmy_context())
.set_id(community.followers_url.into())
.set_total_items(community_followers.len() as u64);
+ let collection = WithContext::new(collection);
Ok(create_apub_response(&collection))
}
use crate::{
check_is_apub_id_valid,
+ context::WithContext,
fetcher::get_or_fetch_and_upsert_actor,
http::{
community::{receive_group_inbox, GroupInboxActivities},
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received shared inbox activity {}", unparsed);
- let activity = serde_json::from_str::<SharedInboxActivities>(&unparsed)?;
- match activity {
+ let activity = serde_json::from_str::<WithContext<SharedInboxActivities>>(&unparsed)?;
+ match activity.inner() {
SharedInboxActivities::GroupInboxActivities(g) => {
receive_group_inbox(g, request, &context).await
}
{
HttpResponse::Ok()
.content_type(APUB_JSON_CONTENT_TYPE)
- .json(data)
+ .json(WithContext::new(data))
}
fn create_apub_tombstone_response<T>(data: &T) -> HttpResponse<Body>
HttpResponse::Gone()
.content_type(APUB_JSON_CONTENT_TYPE)
.status(StatusCode::GONE)
- .json(data)
+ .json(WithContext::new(data))
}
#[derive(Deserialize)]
undo_delete::UndoDeletePrivateMessage,
},
},
- context::lemmy_context,
+ context::WithContext,
generate_outbox_url,
http::{
create_apub_response,
) -> Result<HttpResponse, LemmyError> {
let unparsed = payload_to_string(payload).await?;
info!("Received person inbox activity {}", unparsed);
- let activity = serde_json::from_str::<PersonInboxActivities>(&unparsed)?;
- receive_person_inbox(activity, request, &context).await
+ let activity = serde_json::from_str::<WithContext<PersonInboxActivities>>(&unparsed)?;
+ receive_person_inbox(activity.inner(), request, &context).await
}
pub(in crate::http) async fn receive_person_inbox(
let mut collection = OrderedCollection::new();
collection
.set_many_items(Vec::<Url>::new())
- .set_many_contexts(lemmy_context())
.set_id(generate_outbox_url(&person.actor_id)?.into())
.set_total_items(0_u64);
+ let collection = WithContext::new(collection);
Ok(create_apub_response(&collection))
}
use crate::fetcher::post_or_comment::PostOrComment;
use anyhow::{anyhow, Context};
use lemmy_api_common::blocking;
-use lemmy_apub_lib::{
- activity_queue::send_activity,
- traits::ActorType,
- webfinger::{webfinger_resolve_actor, WebfingerType},
-};
+use lemmy_apub_lib::webfinger::{webfinger_resolve_actor, WebfingerType};
use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
-use log::info;
use serde::Serialize;
use std::net::IpAddr;
use url::{ParseError, Url};
.await??;
Ok(())
}
-
-pub(crate) async fn send_lemmy_activity<T: Serialize>(
- context: &LemmyContext,
- activity: &T,
- activity_id: &Url,
- actor: &dyn ActorType,
- inboxes: Vec<Url>,
- sensitive: bool,
-) -> Result<(), LemmyError> {
- if !context.settings().federation.enabled || inboxes.is_empty() {
- return Ok(());
- }
-
- info!("Sending activity {}", activity_id.to_string());
-
- // Don't send anything to ourselves
- // TODO: this should be a debug assert
- let hostname = context.settings().get_hostname_without_port()?;
- let inboxes: Vec<&Url> = inboxes
- .iter()
- .filter(|i| i.domain().expect("valid inbox url") != hostname)
- .collect();
-
- let serialised_activity = serde_json::to_string(&activity)?;
-
- insert_activity(
- activity_id,
- serialised_activity.clone(),
- true,
- sensitive,
- context.pool(),
- )
- .await?;
-
- send_activity(
- serialised_activity,
- actor,
- inboxes,
- context.client(),
- context.activity_queue(),
- )
- .await
-}
use crate::{
activities::{verify_is_public, verify_person_in_community},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{
community::ApubCommunity,
},
PostOrComment,
};
-use activitystreams::{
- base::AnyBase,
- chrono::NaiveDateTime,
- object::kind::NoteType,
- primitives::OneOrMany,
- public,
- unparsed::Unparsed,
-};
+use activitystreams::{object::kind::NoteType, public, unparsed::Unparsed};
use anyhow::anyhow;
-use chrono::{DateTime, FixedOffset};
+use chrono::{DateTime, FixedOffset, NaiveDateTime};
use html2md::parse_html;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Note {
- /// Necessary to make this optional to make Pleroma Create/Note work.
- /// TODO: change this so that context is not defined in the struct itself, but added in activity
- /// queue and http handlers
- #[serde(rename = "@context")]
- context: Option<OneOrMany<AnyBase>>,
r#type: NoteType,
id: Url,
pub(crate) attributed_to: ObjectId<ApubPerson>,
};
let note = Note {
- context: Some(lemmy_context()),
r#type: NoteType::Note,
id: self.ap_id.to_owned().into_inner(),
attributed_to: ObjectId::new(creator.actor_id),
community_outbox::ApubCommunityOutbox,
CommunityContext,
},
- context::lemmy_context,
fetcher::object_id::ObjectId,
generate_moderators_url,
generate_outbox_url,
};
use activitystreams::{
actor::{kind::GroupType, Endpoints},
- base::AnyBase,
- chrono::NaiveDateTime,
object::kind::ImageType,
- primitives::OneOrMany,
unparsed::Unparsed,
};
-use chrono::{DateTime, FixedOffset};
+use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Group {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(rename = "type")]
kind: GroupType,
pub(crate) id: Url,
});
let group = Group {
- context: lemmy_context(),
kind: GroupType::Group,
id: self.actor_id(),
preferred_username: self.name.clone(),
use crate::{
check_is_apub_id_valid,
- context::lemmy_context,
generate_outbox_url,
objects::{get_summary_from_string_or_source, ImageObject, Source},
};
-use activitystreams::{
- actor::Endpoints,
- base::AnyBase,
- chrono::NaiveDateTime,
- object::{kind::ImageType, Tombstone},
- primitives::OneOrMany,
- unparsed::Unparsed,
-};
-use chrono::{DateTime, FixedOffset};
+use activitystreams::{actor::Endpoints, object::kind::ImageType, unparsed::Unparsed};
+use chrono::{DateTime, FixedOffset, NaiveDateTime};
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
signatures::PublicKey,
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Person {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(rename = "type")]
kind: UserTypes,
id: Url,
impl ApubObject for ApubPerson {
type DataType = LemmyContext;
type ApubType = Person;
- type TombstoneType = Tombstone;
+ type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
Some(self.last_refreshed_at)
});
let person = Person {
- context: lemmy_context(),
kind,
id: self.actor_id.to_owned().into_inner(),
preferred_username: self.name.clone(),
Ok(person)
}
- fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
+ fn to_tombstone(&self) -> Result<(), LemmyError> {
unimplemented!()
}
use crate::{
activities::{verify_is_public, verify_person_in_community},
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{
community::ApubCommunity,
},
};
use activitystreams::{
- base::AnyBase,
object::kind::{ImageType, PageType},
- primitives::OneOrMany,
public,
unparsed::Unparsed,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Page {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
r#type: PageType,
id: Url,
pub(crate) attributed_to: ObjectId<ApubPerson>,
});
let page = Page {
- context: lemmy_context(),
r#type: PageType::Page,
id: self.ap_id.clone().into(),
attributed_to: ObjectId::new(creator.actor_id),
use crate::{
- context::lemmy_context,
fetcher::object_id::ObjectId,
objects::{person::ApubPerson, Source},
};
-use activitystreams::{
- base::AnyBase,
- chrono::NaiveDateTime,
- object::Tombstone,
- primitives::OneOrMany,
- unparsed::Unparsed,
-};
+use activitystreams::unparsed::Unparsed;
use anyhow::anyhow;
-use chrono::{DateTime, FixedOffset};
+use chrono::{DateTime, FixedOffset, NaiveDateTime};
use html2md::parse_html;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ChatMessage {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
r#type: ChatMessageType,
id: Url,
pub(crate) attributed_to: ObjectId<ApubPerson>,
impl ApubObject for ApubPrivateMessage {
type DataType = LemmyContext;
type ApubType = ChatMessage;
- type TombstoneType = Tombstone;
+ type TombstoneType = ();
fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
None
blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??;
let note = ChatMessage {
- context: lemmy_context(),
r#type: ChatMessageType::ChatMessage,
id: self.ap_id.clone().into(),
attributed_to: ObjectId::new(creator.actor_id),
Ok(note)
}
- fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
+ fn to_tombstone(&self) -> Result<(), LemmyError> {
unimplemented!()
}
-use crate::context::lemmy_context;
-use activitystreams::{
- base::AnyBase,
- chrono::{DateTime, FixedOffset, NaiveDateTime},
- object::kind::TombstoneType,
- primitives::OneOrMany,
-};
+use activitystreams::object::kind::TombstoneType;
+use chrono::{DateTime, FixedOffset, NaiveDateTime};
use lemmy_utils::utils::convert_datetime;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Tombstone {
- #[serde(rename = "@context")]
- context: OneOrMany<AnyBase>,
#[serde(rename = "type")]
kind: TombstoneType,
former_type: String,
impl Tombstone {
pub fn new<T: ToString>(former_type: T, updated_time: NaiveDateTime) -> Tombstone {
Tombstone {
- context: lemmy_context(),
kind: TombstoneType::Tombstone,
former_type: former_type.to_string(),
deleted: convert_datetime(updated_time),