mirror of https://github.com/LemmyNet/lemmy.git
make ObjectId a newtype
parent
171d17e00d
commit
13eca1b106
|
@ -10,6 +10,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{comment::Note, FromApub, ToApub},
|
||||
ActorType,
|
||||
};
|
||||
|
@ -26,7 +27,7 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateOrUpdateComment {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: Note,
|
||||
cc: Vec<Url>,
|
||||
|
@ -60,7 +61,7 @@ impl CreateOrUpdateComment {
|
|||
let maa = collect_non_local_mentions(comment, &community, context).await?;
|
||||
|
||||
let create_or_update = CreateOrUpdateComment {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: comment.to_apub(context.pool()).await?,
|
||||
cc: maa.ccs,
|
||||
|
@ -84,11 +85,11 @@ impl ActivityHandler for CreateOrUpdateComment {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = extract_community(&self.cc, context, request_counter).await?;
|
||||
let community_id = ObjectId::<Community>::new(community.actor_id());
|
||||
|
||||
verify_activity(self)?;
|
||||
verify_person_in_community(&self.actor, &community.actor_id(), context, request_counter)
|
||||
.await?;
|
||||
verify_domains_match(&self.actor, self.object.id_unchecked())?;
|
||||
verify_person_in_community(&self.actor, &community_id, context, request_counter).await?;
|
||||
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
|
||||
// TODO: should add a check that the correct community is in cc (probably needs changes to
|
||||
// comment deserialization)
|
||||
self.object.verify(context, request_counter).await?;
|
||||
|
@ -100,7 +101,8 @@ impl ActivityHandler for CreateOrUpdateComment {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let comment = Comment::from_apub(&self.object, context, &self.actor, request_counter).await?;
|
||||
let comment =
|
||||
Comment::from_apub(&self.object, context, self.actor.inner(), request_counter).await?;
|
||||
let recipients = get_notif_recipients(&self.actor, &comment, context, request_counter).await?;
|
||||
let notif_type = match self.kind {
|
||||
CreateOrUpdateType::Create => UserOperationCrud::CreateComment,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{fetcher::dereference_object_id::dereference, ActorType};
|
||||
use crate::{fetcher::object_id::ObjectId, ActorType};
|
||||
use activitystreams::{
|
||||
base::BaseExt,
|
||||
link::{LinkExt, Mention},
|
||||
|
@ -26,14 +26,14 @@ use url::Url;
|
|||
pub mod create_or_update;
|
||||
|
||||
async fn get_notif_recipients(
|
||||
actor: &Url,
|
||||
actor: &ObjectId<Person>,
|
||||
comment: &Comment,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Vec<LocalUserId>, LemmyError> {
|
||||
let post_id = comment.post_id;
|
||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
||||
let actor = dereference::<Person>(actor, context, request_counter).await?;
|
||||
let actor = actor.dereference(context, request_counter).await?;
|
||||
|
||||
// Note:
|
||||
// Although mentions could be gotten from the post tags (they are included there), or the ccs,
|
||||
|
@ -76,14 +76,17 @@ pub async fn collect_non_local_mentions(
|
|||
for mention in &mentions {
|
||||
// TODO should it be fetching it every time?
|
||||
if let Ok(actor_id) = fetch_webfinger_url(mention, context.client()).await {
|
||||
let actor_id: ObjectId<Person> = ObjectId::<Person>::new(actor_id);
|
||||
debug!("mention actor_id: {}", actor_id);
|
||||
addressed_ccs.push(actor_id.to_owned().to_string().parse()?);
|
||||
|
||||
let mention_person = dereference::<Person>(&actor_id, context, &mut 0).await?;
|
||||
let mention_person = actor_id.dereference(context, &mut 0).await?;
|
||||
inboxes.push(mention_person.get_shared_inbox_or_inbox_url());
|
||||
|
||||
let mut mention_tag = Mention::new();
|
||||
mention_tag.set_href(actor_id).set_name(mention.full_name());
|
||||
mention_tag
|
||||
.set_href(actor_id.into())
|
||||
.set_name(mention.full_name());
|
||||
tags.push(mention_tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
generate_moderators_url,
|
||||
ActorType,
|
||||
};
|
||||
|
@ -34,11 +34,11 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddMod {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: Url,
|
||||
object: ObjectId<Person>,
|
||||
target: Url,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: AddType,
|
||||
id: Url,
|
||||
|
@ -57,11 +57,11 @@ impl AddMod {
|
|||
) -> Result<(), LemmyError> {
|
||||
let id = generate_activity_id(AddType::Add)?;
|
||||
let add = AddMod {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: added_mod.actor_id(),
|
||||
object: ObjectId::<Person>::new(added_mod.actor_id()),
|
||||
target: generate_moderators_url(&community.actor_id)?.into(),
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: AddType::Add,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
@ -84,7 +84,7 @@ impl ActivityHandler for AddMod {
|
|||
verify_activity(self)?;
|
||||
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
|
||||
verify_add_remove_moderator_target(&self.target, self.cc[0].clone())?;
|
||||
verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -93,8 +93,8 @@ impl ActivityHandler for AddMod {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = dereference::<Community>(&self.cc[0], context, request_counter).await?;
|
||||
let new_mod = dereference::<Person>(&self.object, context, request_counter).await?;
|
||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||
let new_mod = self.object.dereference(context, request_counter).await?;
|
||||
|
||||
// If we had to refetch the community while parsing the activity, then the new mod has already
|
||||
// been added. Skip it here as it would result in a duplicate key error.
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
http::is_activity_already_known,
|
||||
insert_activity,
|
||||
ActorType,
|
||||
|
@ -57,7 +58,7 @@ pub enum AnnouncableActivities {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AnnounceActivity {
|
||||
actor: Url,
|
||||
actor: ObjectId<Community>,
|
||||
to: [PublicUrl; 1],
|
||||
object: AnnouncableActivities,
|
||||
cc: Vec<Url>,
|
||||
|
@ -78,7 +79,7 @@ impl AnnounceActivity {
|
|||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let announce = AnnounceActivity {
|
||||
actor: community.actor_id(),
|
||||
actor: ObjectId::<Community>::new(community.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object,
|
||||
cc: vec![community.followers_url()],
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -38,10 +38,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockUserFromCommunity {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
pub(in crate::activities::community) object: Url,
|
||||
cc: [Url; 1],
|
||||
pub(in crate::activities::community) object: ObjectId<Person>,
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: BlockType,
|
||||
id: Url,
|
||||
|
@ -58,10 +58,10 @@ impl BlockUserFromCommunity {
|
|||
actor: &Person,
|
||||
) -> Result<BlockUserFromCommunity, LemmyError> {
|
||||
Ok(BlockUserFromCommunity {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: target.actor_id(),
|
||||
cc: [community.actor_id()],
|
||||
object: ObjectId::<Person>::new(target.actor_id()),
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: BlockType::Block,
|
||||
id: generate_activity_id(BlockType::Block)?,
|
||||
context: lemmy_context(),
|
||||
|
@ -102,8 +102,8 @@ impl ActivityHandler for BlockUserFromCommunity {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = dereference::<Community>(&self.cc[0], context, request_counter).await?;
|
||||
let blocked_user = dereference::<Person>(&self.object, context, request_counter).await?;
|
||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||
let blocked_user = self.object.dereference(context, request_counter).await?;
|
||||
|
||||
let community_user_ban_form = CommunityPersonBanForm {
|
||||
community_id: community.id,
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
generate_moderators_url,
|
||||
ActorType,
|
||||
};
|
||||
|
@ -35,10 +35,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RemoveMod {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
pub(in crate::activities) object: Url,
|
||||
cc: [Url; 1],
|
||||
pub(in crate::activities) object: ObjectId<Person>,
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: RemoveType,
|
||||
// if target is set, this is means remove mod from community
|
||||
|
@ -59,13 +59,13 @@ impl RemoveMod {
|
|||
) -> Result<(), LemmyError> {
|
||||
let id = generate_activity_id(RemoveType::Remove)?;
|
||||
let remove = RemoveMod {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: removed_mod.actor_id(),
|
||||
object: ObjectId::<Person>::new(removed_mod.actor_id()),
|
||||
target: Some(generate_moderators_url(&community.actor_id)?.into()),
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: RemoveType::Remove,
|
||||
unparsed: Default::default(),
|
||||
};
|
||||
|
@ -87,10 +87,10 @@ impl ActivityHandler for RemoveMod {
|
|||
if let Some(target) = &self.target {
|
||||
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
|
||||
verify_add_remove_moderator_target(target, self.cc[0].clone())?;
|
||||
verify_add_remove_moderator_target(target, &self.cc[0])?;
|
||||
} else {
|
||||
verify_delete_activity(
|
||||
&self.object,
|
||||
self.object.inner(),
|
||||
self,
|
||||
&self.cc[0],
|
||||
true,
|
||||
|
@ -108,8 +108,8 @@ impl ActivityHandler for RemoveMod {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
if self.target.is_some() {
|
||||
let community = dereference::<Community>(&self.cc[0], context, request_counter).await?;
|
||||
let remove_mod = dereference::<Person>(&self.object, context, request_counter).await?;
|
||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||
let remove_mod = self.object.dereference(context, request_counter).await?;
|
||||
|
||||
let form = CommunityModeratorForm {
|
||||
community_id: community.id,
|
||||
|
@ -122,7 +122,14 @@ impl ActivityHandler for RemoveMod {
|
|||
// TODO: send websocket notification about removed mod
|
||||
Ok(())
|
||||
} else {
|
||||
receive_remove_action(&self.actor, &self.object, None, context, request_counter).await
|
||||
receive_remove_action(
|
||||
&self.actor,
|
||||
self.object.inner(),
|
||||
None,
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -32,10 +32,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoBlockUserFromCommunity {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: BlockUserFromCommunity,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
id: Url,
|
||||
|
@ -56,10 +56,10 @@ impl UndoBlockUserFromCommunity {
|
|||
|
||||
let id = generate_activity_id(UndoType::Undo)?;
|
||||
let undo = UndoBlockUserFromCommunity {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: block,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
@ -91,8 +91,12 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = dereference::<Community>(&self.cc[0], context, request_counter).await?;
|
||||
let blocked_user = dereference::<Person>(&self.object.object, context, request_counter).await?;
|
||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||
let blocked_user = self
|
||||
.object
|
||||
.object
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
|
||||
let community_user_ban_form = CommunityPersonBanForm {
|
||||
community_id: community.id,
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{community::Group, ToApub},
|
||||
ActorType,
|
||||
};
|
||||
|
@ -34,11 +35,11 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpdateCommunity {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
// TODO: would be nice to use a separate struct here, which only contains the fields updated here
|
||||
object: Group,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: UpdateType,
|
||||
id: Url,
|
||||
|
@ -56,10 +57,10 @@ impl UpdateCommunity {
|
|||
) -> Result<(), LemmyError> {
|
||||
let id = generate_activity_id(UpdateType::Update)?;
|
||||
let update = UpdateCommunity {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: community.to_apub(context.pool()).await?,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: UpdateType::Update,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -62,10 +62,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Delete {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
pub(in crate::activities::deletion) object: Url,
|
||||
pub(in crate::activities::deletion) cc: [Url; 1],
|
||||
pub(in crate::activities::deletion) cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: DeleteType,
|
||||
/// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
|
||||
|
@ -138,10 +138,10 @@ impl Delete {
|
|||
summary: Option<String>,
|
||||
) -> Result<Delete, LemmyError> {
|
||||
Ok(Delete {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: object_id,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: DeleteType::Delete,
|
||||
summary,
|
||||
id: generate_activity_id(DeleteType::Delete)?,
|
||||
|
@ -165,13 +165,13 @@ impl Delete {
|
|||
}
|
||||
|
||||
pub(in crate::activities) async fn receive_remove_action(
|
||||
actor: &Url,
|
||||
actor: &ObjectId<Person>,
|
||||
object: &Url,
|
||||
reason: Option<String>,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(actor, context, request_counter).await?;
|
||||
let actor = actor.dereference(context, request_counter).await?;
|
||||
use UserOperationCrud::*;
|
||||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
verify_mod_action,
|
||||
verify_person_in_community,
|
||||
},
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use lemmy_api_common::blocking;
|
||||
|
@ -99,22 +99,22 @@ impl DeletableObjects {
|
|||
pub(in crate::activities) async fn verify_delete_activity(
|
||||
object: &Url,
|
||||
activity: &dyn ActivityFields,
|
||||
community_id: &Url,
|
||||
community_id: &ObjectId<Community>,
|
||||
is_mod_action: bool,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let object = DeletableObjects::read_from_db(object, context).await?;
|
||||
let actor = ObjectId::<Person>::new(activity.actor().clone());
|
||||
match object {
|
||||
DeletableObjects::Community(c) => {
|
||||
if c.local {
|
||||
// can only do this check for local community, in remote case it would try to fetch the
|
||||
// deleted community (which fails)
|
||||
verify_person_in_community(activity.actor(), community_id, context, request_counter)
|
||||
.await?;
|
||||
verify_person_in_community(&actor, community_id, context, request_counter).await?;
|
||||
}
|
||||
// community deletion is always a mod (or admin) action
|
||||
verify_mod_action(activity.actor(), c.actor_id(), context).await?;
|
||||
verify_mod_action(&actor, ObjectId::<Community>::new(c.actor_id()), context).await?;
|
||||
}
|
||||
DeletableObjects::Post(p) => {
|
||||
verify_delete_activity_post_or_comment(
|
||||
|
@ -145,14 +145,15 @@ pub(in crate::activities) async fn verify_delete_activity(
|
|||
async fn verify_delete_activity_post_or_comment(
|
||||
activity: &dyn ActivityFields,
|
||||
object_id: &Url,
|
||||
community_id: &Url,
|
||||
community_id: &ObjectId<Community>,
|
||||
is_mod_action: bool,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_person_in_community(activity.actor(), community_id, context, request_counter).await?;
|
||||
let actor = ObjectId::<Person>::new(activity.actor().clone());
|
||||
verify_person_in_community(&actor, community_id, context, request_counter).await?;
|
||||
if is_mod_action {
|
||||
verify_mod_action(activity.actor(), community_id.clone(), context).await?;
|
||||
verify_mod_action(&actor, community_id.clone(), context).await?;
|
||||
} else {
|
||||
// domain of post ap_id and post.creator ap_id are identical, so we just check the former
|
||||
verify_domains_match(activity.actor(), object_id)?;
|
||||
|
@ -171,7 +172,7 @@ struct WebsocketMessages {
|
|||
/// because of the mod log
|
||||
async fn receive_delete_action(
|
||||
object: &Url,
|
||||
actor: &Url,
|
||||
actor: &ObjectId<Person>,
|
||||
ws_messages: WebsocketMessages,
|
||||
deleted: bool,
|
||||
context: &LemmyContext,
|
||||
|
@ -180,7 +181,7 @@ async fn receive_delete_action(
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
let mod_ = dereference::<Person>(actor, context, request_counter).await?;
|
||||
let mod_ = actor.dereference(context, request_counter).await?;
|
||||
let object = community.actor_id();
|
||||
send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -38,10 +39,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoDelete {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: Delete,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
id: Url,
|
||||
|
@ -109,10 +110,10 @@ impl UndoDelete {
|
|||
|
||||
let id = generate_activity_id(UndoType::Undo)?;
|
||||
let undo = UndoDelete {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Community>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -31,8 +31,8 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AcceptFollowCommunity {
|
||||
actor: Url,
|
||||
to: Url,
|
||||
actor: ObjectId<Community>,
|
||||
to: ObjectId<Person>,
|
||||
object: FollowCommunity,
|
||||
#[serde(rename = "type")]
|
||||
kind: AcceptType,
|
||||
|
@ -57,8 +57,8 @@ impl AcceptFollowCommunity {
|
|||
.await??;
|
||||
|
||||
let accept = AcceptFollowCommunity {
|
||||
actor: community.actor_id(),
|
||||
to: person.actor_id(),
|
||||
actor: ObjectId::<Community>::new(community.actor_id()),
|
||||
to: ObjectId::<Person>::new(person.actor_id()),
|
||||
object: follow,
|
||||
kind: AcceptType::Accept,
|
||||
id: generate_activity_id(AcceptType::Accept)?,
|
||||
|
@ -78,8 +78,8 @@ impl ActivityHandler for AcceptFollowCommunity {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_urls_match(&self.to, self.object.actor())?;
|
||||
verify_urls_match(&self.actor, &self.object.to)?;
|
||||
verify_urls_match(self.to.inner(), self.object.actor())?;
|
||||
verify_urls_match(self.actor(), self.object.to.inner())?;
|
||||
verify_community(&self.actor, context, request_counter).await?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
|
@ -90,8 +90,8 @@ impl ActivityHandler for AcceptFollowCommunity {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Community>(&self.actor, context, request_counter).await?;
|
||||
let to = dereference::<Person>(&self.to, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let to = self.to.dereference(context, request_counter).await?;
|
||||
// This will throw an error if no follow was requested
|
||||
blocking(context.pool(), move |conn| {
|
||||
CommunityFollower::follow_accepted(conn, actor.id, to.id)
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -31,9 +31,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FollowCommunity {
|
||||
actor: Url,
|
||||
pub(in crate::activities::following) to: Url,
|
||||
pub(in crate::activities::following) object: Url,
|
||||
actor: ObjectId<Person>,
|
||||
// TODO: is there any reason to put the same community id twice, in to and object?
|
||||
pub(in crate::activities::following) to: ObjectId<Community>,
|
||||
pub(in crate::activities::following) object: ObjectId<Community>,
|
||||
#[serde(rename = "type")]
|
||||
kind: FollowType,
|
||||
id: Url,
|
||||
|
@ -49,9 +50,9 @@ impl FollowCommunity {
|
|||
community: &Community,
|
||||
) -> Result<FollowCommunity, LemmyError> {
|
||||
Ok(FollowCommunity {
|
||||
actor: actor.actor_id(),
|
||||
to: community.actor_id(),
|
||||
object: community.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: ObjectId::<Community>::new(community.actor_id()),
|
||||
object: ObjectId::<Community>::new(community.actor_id()),
|
||||
kind: FollowType::Follow,
|
||||
id: generate_activity_id(FollowType::Follow)?,
|
||||
context: lemmy_context(),
|
||||
|
@ -87,7 +88,7 @@ impl ActivityHandler for FollowCommunity {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_urls_match(&self.to, &self.object)?;
|
||||
verify_urls_match(self.to.inner(), self.object.inner())?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -97,8 +98,8 @@ impl ActivityHandler for FollowCommunity {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(&self.actor, context, request_counter).await?;
|
||||
let community = dereference::<Community>(&self.object, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let community = self.object.dereference(context, request_counter).await?;
|
||||
let community_follower_form = CommunityFollowerForm {
|
||||
community_id: community.id,
|
||||
person_id: actor.id,
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -31,8 +31,8 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoFollowCommunity {
|
||||
actor: Url,
|
||||
to: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: ObjectId<Community>,
|
||||
object: FollowCommunity,
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
|
@ -51,8 +51,8 @@ impl UndoFollowCommunity {
|
|||
) -> Result<(), LemmyError> {
|
||||
let object = FollowCommunity::new(actor, community)?;
|
||||
let undo = UndoFollowCommunity {
|
||||
actor: actor.actor_id(),
|
||||
to: community.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: ObjectId::<Community>::new(community.actor_id()),
|
||||
object,
|
||||
kind: UndoType::Undo,
|
||||
id: generate_activity_id(UndoType::Undo)?,
|
||||
|
@ -72,8 +72,8 @@ impl ActivityHandler for UndoFollowCommunity {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_urls_match(&self.to, &self.object.object)?;
|
||||
verify_urls_match(&self.actor, self.object.actor())?;
|
||||
verify_urls_match(self.to.inner(), self.object.object.inner())?;
|
||||
verify_urls_match(self.actor(), self.object.actor())?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
|
@ -84,8 +84,8 @@ impl ActivityHandler for UndoFollowCommunity {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(&self.actor, context, request_counter).await?;
|
||||
let community = dereference::<Community>(&self.to, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let community = self.to.dereference(context, request_counter).await?;
|
||||
|
||||
let community_follower_form = CommunityFollowerForm {
|
||||
community_id: community.id,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
check_community_or_site_ban,
|
||||
check_is_apub_id_valid,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
generate_moderators_url,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
|
@ -39,11 +39,11 @@ pub enum CreateOrUpdateType {
|
|||
/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
|
||||
/// doesn't have a site ban.
|
||||
async fn verify_person(
|
||||
person_id: &Url,
|
||||
person_id: &ObjectId<Person>,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let person = dereference::<Person>(person_id, context, request_counter).await?;
|
||||
let person = person_id.dereference(context, request_counter).await?;
|
||||
if person.banned {
|
||||
return Err(anyhow!("Person {} is banned", person_id).into());
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ pub(crate) async fn extract_community(
|
|||
let mut cc_iter = cc.iter();
|
||||
loop {
|
||||
if let Some(cid) = cc_iter.next() {
|
||||
if let Ok(c) = dereference(cid, context, request_counter).await {
|
||||
let cid = ObjectId::<Community>::new(cid.clone());
|
||||
if let Ok(c) = cid.dereference(context, request_counter).await {
|
||||
break Ok(c);
|
||||
}
|
||||
} else {
|
||||
|
@ -70,23 +71,23 @@ pub(crate) async fn extract_community(
|
|||
/// Fetches the person and community to verify their type, then checks if person is banned from site
|
||||
/// or community.
|
||||
pub(crate) async fn verify_person_in_community(
|
||||
person_id: &Url,
|
||||
community_id: &Url,
|
||||
person_id: &ObjectId<Person>,
|
||||
community_id: &ObjectId<Community>,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = dereference::<Community>(community_id, context, request_counter).await?;
|
||||
let person = dereference::<Person>(person_id, context, request_counter).await?;
|
||||
let community = community_id.dereference(context, request_counter).await?;
|
||||
let person = person_id.dereference(context, request_counter).await?;
|
||||
check_community_or_site_ban(&person, community.id, context.pool()).await
|
||||
}
|
||||
|
||||
/// Simply check that the url actually refers to a valid group.
|
||||
async fn verify_community(
|
||||
community_id: &Url,
|
||||
community_id: &ObjectId<Community>,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
dereference::<Community>(community_id, context, request_counter).await?;
|
||||
community_id.dereference(context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -100,12 +101,12 @@ fn verify_activity(activity: &dyn ActivityFields) -> Result<(), LemmyError> {
|
|||
/// because in case of remote communities, admins can also perform mod actions. As admin status
|
||||
/// is not federated, we cant verify their actions remotely.
|
||||
pub(crate) async fn verify_mod_action(
|
||||
actor_id: &Url,
|
||||
community: Url,
|
||||
actor_id: &ObjectId<Person>,
|
||||
community_id: ObjectId<Community>,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read_from_apub_id(conn, &community.into())
|
||||
Community::read_from_apub_id(conn, &community_id.into())
|
||||
})
|
||||
.await??;
|
||||
|
||||
|
@ -133,8 +134,11 @@ pub(crate) async fn verify_mod_action(
|
|||
|
||||
/// For Add/Remove community moderator activities, check that the target field actually contains
|
||||
/// /c/community/moderators. Any different values are unsupported.
|
||||
fn verify_add_remove_moderator_target(target: &Url, community: Url) -> Result<(), LemmyError> {
|
||||
if target != &generate_moderators_url(&community.into())?.into_inner() {
|
||||
fn verify_add_remove_moderator_target(
|
||||
target: &Url,
|
||||
community: &ObjectId<Community>,
|
||||
) -> Result<(), LemmyError> {
|
||||
if target != &generate_moderators_url(&community.clone().into())?.into_inner() {
|
||||
return Err(anyhow!("Unkown target url").into());
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::{
|
||||
activities::{
|
||||
community::announce::AnnouncableActivities,
|
||||
extract_community,
|
||||
generate_activity_id,
|
||||
verify_activity,
|
||||
verify_mod_action,
|
||||
|
@ -10,7 +9,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{post::Page, FromApub, ToApub},
|
||||
ActorType,
|
||||
};
|
||||
|
@ -34,10 +33,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateOrUpdatePost {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: Page,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: CreateOrUpdateType,
|
||||
id: Url,
|
||||
|
@ -62,10 +61,10 @@ impl CreateOrUpdatePost {
|
|||
|
||||
let id = generate_activity_id(kind.clone())?;
|
||||
let create_or_update = CreateOrUpdatePost {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: post.to_apub(context.pool()).await?,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
@ -85,13 +84,12 @@ impl ActivityHandler for CreateOrUpdatePost {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
let community = extract_community(&self.cc, context, request_counter).await?;
|
||||
let community_id = community.actor_id();
|
||||
verify_person_in_community(&self.actor, &community_id, context, request_counter).await?;
|
||||
let community = self.cc[0].dereference(context, request_counter).await?;
|
||||
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||
match self.kind {
|
||||
CreateOrUpdateType::Create => {
|
||||
verify_domains_match(&self.actor, self.object.id_unchecked())?;
|
||||
verify_urls_match(&self.actor, &self.object.attributed_to)?;
|
||||
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
|
||||
verify_urls_match(self.actor(), self.object.attributed_to.inner())?;
|
||||
// Check that the post isnt locked or stickied, as that isnt possible for newly created posts.
|
||||
// However, when fetching a remote post we generate a new create activity with the current
|
||||
// locked/stickied value, so this check may fail. So only check if its a local community,
|
||||
|
@ -105,10 +103,10 @@ impl ActivityHandler for CreateOrUpdatePost {
|
|||
CreateOrUpdateType::Update => {
|
||||
let is_mod_action = self.object.is_mod_action(context.pool()).await?;
|
||||
if is_mod_action {
|
||||
verify_mod_action(&self.actor, community_id, context).await?;
|
||||
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
|
||||
} else {
|
||||
verify_domains_match(&self.actor, self.object.id_unchecked())?;
|
||||
verify_urls_match(&self.actor, &self.object.attributed_to)?;
|
||||
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
|
||||
verify_urls_match(self.actor(), self.object.attributed_to.inner())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +119,7 @@ impl ActivityHandler for CreateOrUpdatePost {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(&self.actor, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let post = Post::from_apub(&self.object, context, &actor.actor_id(), request_counter).await?;
|
||||
|
||||
let notif_type = match self.kind {
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
activities::{generate_activity_id, verify_activity, verify_person, CreateOrUpdateType},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{private_message::Note, FromApub, ToApub},
|
||||
ActorType,
|
||||
};
|
||||
|
@ -21,9 +22,8 @@ pub struct CreateOrUpdatePrivateMessage {
|
|||
#[serde(rename = "@context")]
|
||||
pub context: OneOrMany<AnyBase>,
|
||||
id: Url,
|
||||
actor: Url,
|
||||
to: Url,
|
||||
cc: [Url; 0],
|
||||
actor: ObjectId<Person>,
|
||||
to: ObjectId<Person>,
|
||||
object: Note,
|
||||
#[serde(rename = "type")]
|
||||
kind: CreateOrUpdateType,
|
||||
|
@ -46,9 +46,8 @@ impl CreateOrUpdatePrivateMessage {
|
|||
let create_or_update = CreateOrUpdatePrivateMessage {
|
||||
context: lemmy_context(),
|
||||
id: id.clone(),
|
||||
actor: actor.actor_id(),
|
||||
to: recipient.actor_id(),
|
||||
cc: [],
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: ObjectId::<Person>::new(recipient.actor_id()),
|
||||
object: private_message.to_apub(context.pool()).await?,
|
||||
kind,
|
||||
unparsed: Default::default(),
|
||||
|
@ -66,7 +65,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
|
|||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
verify_domains_match(&self.actor, self.object.id_unchecked())?;
|
||||
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -77,7 +76,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let private_message =
|
||||
PrivateMessage::from_apub(&self.object, context, &self.actor, request_counter).await?;
|
||||
PrivateMessage::from_apub(&self.object, context, self.actor.inner(), request_counter).await?;
|
||||
|
||||
let notif_type = match self.kind {
|
||||
CreateOrUpdateType::Create => UserOperationCrud::CreatePrivateMessage,
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
activities::{generate_activity_id, verify_activity, verify_person},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -22,8 +23,8 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeletePrivateMessage {
|
||||
actor: Url,
|
||||
to: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: ObjectId<Person>,
|
||||
pub(in crate::activities::private_message) object: Url,
|
||||
#[serde(rename = "type")]
|
||||
kind: DeleteType,
|
||||
|
@ -40,8 +41,8 @@ impl DeletePrivateMessage {
|
|||
pm: &PrivateMessage,
|
||||
) -> Result<DeletePrivateMessage, LemmyError> {
|
||||
Ok(DeletePrivateMessage {
|
||||
actor: actor.actor_id(),
|
||||
to: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: ObjectId::<Person>::new(actor.actor_id()),
|
||||
object: pm.ap_id.clone().into(),
|
||||
kind: DeleteType::Delete,
|
||||
id: generate_activity_id(DeleteType::Delete)?,
|
||||
|
@ -74,7 +75,7 @@ impl ActivityHandler for DeletePrivateMessage {
|
|||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
verify_domains_match(&self.actor, &self.object)?;
|
||||
verify_domains_match(self.actor.inner(), &self.object)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_activity_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -27,8 +28,8 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoDeletePrivateMessage {
|
||||
actor: Url,
|
||||
to: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: ObjectId<Person>,
|
||||
object: DeletePrivateMessage,
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
|
@ -52,8 +53,8 @@ impl UndoDeletePrivateMessage {
|
|||
let object = DeletePrivateMessage::new(actor, pm)?;
|
||||
let id = generate_activity_id(UndoType::Undo)?;
|
||||
let undo = UndoDeletePrivateMessage {
|
||||
actor: actor.actor_id(),
|
||||
to: recipient.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: ObjectId::<Person>::new(recipient.actor_id()),
|
||||
object,
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
|
@ -74,8 +75,8 @@ impl ActivityHandler for UndoDeletePrivateMessage {
|
|||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
verify_urls_match(&self.actor, self.object.actor())?;
|
||||
verify_domains_match(&self.actor, &self.object.object)?;
|
||||
verify_urls_match(self.actor(), self.object.actor())?;
|
||||
verify_domains_match(self.actor(), &self.object.object)?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use crate::activities::{
|
||||
community::remove_mod::RemoveMod,
|
||||
deletion::{undo_delete::UndoDelete, verify_delete_activity},
|
||||
verify_activity,
|
||||
use crate::{
|
||||
activities::{
|
||||
community::remove_mod::RemoveMod,
|
||||
deletion::{undo_delete::UndoDelete, verify_delete_activity},
|
||||
verify_activity,
|
||||
},
|
||||
fetcher::object_id::ObjectId,
|
||||
};
|
||||
use activitystreams::{
|
||||
activity::kind::UndoType,
|
||||
|
@ -10,6 +13,7 @@ use activitystreams::{
|
|||
unparsed::Unparsed,
|
||||
};
|
||||
use lemmy_apub_lib::{values::PublicUrl, ActivityFields, ActivityHandler};
|
||||
use lemmy_db_schema::source::{community::Community, person::Person};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -18,11 +22,11 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoRemovePostCommentOrCommunity {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
// Note, there is no such thing as Undo/Remove/Mod, so we ignore that
|
||||
object: RemoveMod,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
id: Url,
|
||||
|
@ -43,7 +47,7 @@ impl ActivityHandler for UndoRemovePostCommentOrCommunity {
|
|||
self.object.verify(context, request_counter).await?;
|
||||
|
||||
verify_delete_activity(
|
||||
&self.object.object,
|
||||
self.object.object.inner(),
|
||||
self,
|
||||
&self.cc[0],
|
||||
true,
|
||||
|
@ -59,6 +63,6 @@ impl ActivityHandler for UndoRemovePostCommentOrCommunity {
|
|||
context: &LemmyContext,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
UndoDelete::receive_undo_remove_action(&self.object.object, context).await
|
||||
UndoDelete::receive_undo_remove_action(self.object.object.inner(), context).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
PostOrComment,
|
||||
};
|
||||
|
@ -38,10 +38,10 @@ use url::Url;
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoVote {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
object: Vote,
|
||||
cc: [Url; 1],
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
kind: UndoType,
|
||||
id: Url,
|
||||
|
@ -67,10 +67,10 @@ impl UndoVote {
|
|||
let object = Vote::new(object, actor, &community, kind.clone())?;
|
||||
let id = generate_activity_id(UndoType::Undo)?;
|
||||
let undo_vote = UndoVote {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object,
|
||||
cc: [community.actor_id()],
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
context: lemmy_context(),
|
||||
|
@ -90,7 +90,7 @@ impl ActivityHandler for UndoVote {
|
|||
) -> Result<(), LemmyError> {
|
||||
verify_activity(self)?;
|
||||
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
|
||||
verify_urls_match(&self.actor, self.object.actor())?;
|
||||
verify_urls_match(self.actor(), self.object.actor())?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -100,9 +100,12 @@ impl ActivityHandler for UndoVote {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(&self.actor, context, request_counter).await?;
|
||||
let object =
|
||||
dereference::<PostOrComment>(&self.object.object, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let object = self
|
||||
.object
|
||||
.object
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
match object {
|
||||
PostOrComment::Post(p) => undo_vote_post(actor, p.deref(), context).await,
|
||||
PostOrComment::Comment(c) => undo_vote_comment(actor, c.deref(), context).await,
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
activity_queue::send_to_community_new,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
ActorType,
|
||||
PostOrComment,
|
||||
};
|
||||
|
@ -58,10 +58,10 @@ impl From<&VoteType> for i16 {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Vote {
|
||||
actor: Url,
|
||||
actor: ObjectId<Person>,
|
||||
to: [PublicUrl; 1],
|
||||
pub(in crate::activities::voting) object: Url,
|
||||
cc: [Url; 1],
|
||||
pub(in crate::activities::voting) object: ObjectId<PostOrComment>,
|
||||
cc: [ObjectId<Community>; 1],
|
||||
#[serde(rename = "type")]
|
||||
pub(in crate::activities::voting) kind: VoteType,
|
||||
id: Url,
|
||||
|
@ -79,10 +79,10 @@ impl Vote {
|
|||
kind: VoteType,
|
||||
) -> Result<Vote, LemmyError> {
|
||||
Ok(Vote {
|
||||
actor: actor.actor_id(),
|
||||
actor: ObjectId::<Person>::new(actor.actor_id()),
|
||||
to: [PublicUrl::Public],
|
||||
object: object.ap_id(),
|
||||
cc: [community.actor_id()],
|
||||
object: ObjectId::<PostOrComment>::new(object.ap_id()),
|
||||
cc: [ObjectId::<Community>::new(community.actor_id())],
|
||||
kind: kind.clone(),
|
||||
id: generate_activity_id(kind)?,
|
||||
context: lemmy_context(),
|
||||
|
@ -126,8 +126,8 @@ impl ActivityHandler for Vote {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let actor = dereference::<Person>(&self.actor, context, request_counter).await?;
|
||||
let object = dereference::<PostOrComment>(&self.object, context, request_counter).await?;
|
||||
let actor = self.actor.dereference(context, request_counter).await?;
|
||||
let object = self.object.dereference(context, request_counter).await?;
|
||||
match object {
|
||||
PostOrComment::Post(p) => vote_post(&self.kind, actor, p.deref(), context).await,
|
||||
PostOrComment::Comment(c) => vote_comment(&self.kind, actor, c.deref(), context).await,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
activities::community::announce::AnnounceActivity,
|
||||
fetcher::{dereference_object_id::dereference, fetch::fetch_remote_object},
|
||||
fetcher::{fetch::fetch_remote_object, object_id::ObjectId},
|
||||
objects::community::Group,
|
||||
};
|
||||
use activitystreams::collection::{CollectionExt, OrderedCollection};
|
||||
|
@ -44,8 +44,9 @@ pub(crate) async fn update_community_mods(
|
|||
}
|
||||
|
||||
// Add new mods to database which have been added to moderators collection
|
||||
for mod_uri in new_moderators {
|
||||
let mod_user = dereference::<Person>(&mod_uri, context, request_counter).await?;
|
||||
for mod_id in new_moderators {
|
||||
let mod_id = ObjectId::<Person>::new::<Person, Url>(mod_id);
|
||||
let mod_user = mod_id.dereference(context, request_counter).await?;
|
||||
|
||||
if !current_moderators
|
||||
.clone()
|
||||
|
@ -91,7 +92,7 @@ pub(crate) async fn fetch_community_outbox(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn fetch_community_mods(
|
||||
async fn fetch_community_mods(
|
||||
context: &LemmyContext,
|
||||
group: &Group,
|
||||
recursion_counter: &mut i32,
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
use crate::{fetcher::should_refetch_actor, objects::FromApub, APUB_JSON_CONTENT_TYPE};
|
||||
use anyhow::anyhow;
|
||||
use diesel::NotFound;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_db_queries::{ApubObject, DbPool};
|
||||
use lemmy_utils::{request::retry, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use log::debug;
|
||||
use reqwest::StatusCode;
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
/// Maximum number of HTTP requests allowed to handle a single incoming activity (or a single object
|
||||
/// fetch through the search). This should be configurable.
|
||||
static REQUEST_LIMIT: i32 = 25;
|
||||
|
||||
/// Fetches an activitypub object, either from local database (if possible), or over http.
|
||||
pub(crate) async fn dereference<Kind>(
|
||||
id: &Url,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Kind, LemmyError>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
let db_object = dereference_locally::<Kind>(id.clone(), context.pool()).await?;
|
||||
// if its a local object, only fetch it from the database and not over http
|
||||
if id.domain() == Some(&Settings::get().get_hostname_without_port()?) {
|
||||
return match db_object {
|
||||
None => Err(NotFound {}.into()),
|
||||
Some(o) => Ok(o),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(object) = db_object {
|
||||
if let Some(last_refreshed_at) = object.last_refreshed_at() {
|
||||
// TODO: rename to should_refetch_object()
|
||||
if should_refetch_actor(last_refreshed_at) {
|
||||
debug!("Refetching remote object {}", id);
|
||||
return dereference_remotely(id, context, request_counter).await;
|
||||
}
|
||||
}
|
||||
Ok(object)
|
||||
} else {
|
||||
debug!("Fetching remote object {}", id);
|
||||
dereference_remotely(id, context, request_counter).await
|
||||
}
|
||||
}
|
||||
|
||||
/// returning none means the object was not found in local db
|
||||
async fn dereference_locally<Kind>(id: Url, pool: &DbPool) -> Result<Option<Kind>, LemmyError>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
let object = blocking(pool, move |conn| {
|
||||
ApubObject::read_from_apub_id(conn, &id.into())
|
||||
})
|
||||
.await?;
|
||||
match object {
|
||||
Ok(o) => Ok(Some(o)),
|
||||
Err(NotFound {}) => Ok(None),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn dereference_remotely<Kind>(
|
||||
id: &Url,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Kind, LemmyError>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
// dont fetch local objects this way
|
||||
debug_assert!(id.domain() != Some(&Settings::get().hostname));
|
||||
|
||||
*request_counter += 1;
|
||||
if *request_counter > REQUEST_LIMIT {
|
||||
return Err(LemmyError::from(anyhow!("Request limit reached")));
|
||||
}
|
||||
|
||||
let res = retry(|| {
|
||||
context
|
||||
.client()
|
||||
.get(id.as_str())
|
||||
.header("Accept", APUB_JSON_CONTENT_TYPE)
|
||||
.timeout(Duration::from_secs(60))
|
||||
.send()
|
||||
})
|
||||
.await?;
|
||||
|
||||
if res.status() == StatusCode::GONE {
|
||||
mark_object_deleted::<Kind>(id, context).await?;
|
||||
return Err(anyhow!("Fetched remote object {} which was deleted", id.to_string()).into());
|
||||
}
|
||||
|
||||
let res2: Kind::ApubType = res.json().await?;
|
||||
|
||||
Ok(Kind::from_apub(&res2, context, id, request_counter).await?)
|
||||
}
|
||||
|
||||
async fn mark_object_deleted<Kind>(_id: &Url, _context: &LemmyContext) -> Result<(), LemmyError>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
{
|
||||
// TODO: need to move methods update_deleted, update_removed etc into a trait to use them here.
|
||||
// also, how do we know if the object was deleted vs removed?
|
||||
todo!()
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
pub mod community;
|
||||
pub mod dereference_object_id;
|
||||
mod fetch;
|
||||
pub mod object_id;
|
||||
pub mod post_or_comment;
|
||||
pub mod search;
|
||||
|
||||
use crate::{
|
||||
fetcher::{dereference_object_id::dereference, fetch::FetchError},
|
||||
fetcher::{fetch::FetchError, object_id::ObjectId},
|
||||
ActorType,
|
||||
};
|
||||
use chrono::NaiveDateTime;
|
||||
|
@ -42,14 +42,19 @@ where
|
|||
/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
|
||||
/// Otherwise it is fetched from the remote instance, stored and returned.
|
||||
pub(crate) async fn get_or_fetch_and_upsert_actor(
|
||||
apub_id: &Url,
|
||||
apub_id: Url,
|
||||
context: &LemmyContext,
|
||||
recursion_counter: &mut i32,
|
||||
) -> Result<Box<dyn ActorType>, LemmyError> {
|
||||
let community = dereference::<Community>(apub_id, context, recursion_counter).await;
|
||||
let community_id: ObjectId<Community> = ObjectId::<Community>::new(apub_id.clone());
|
||||
let community = community_id.dereference(context, recursion_counter).await;
|
||||
let actor: Box<dyn ActorType> = match community {
|
||||
Ok(c) => Box::new(c),
|
||||
Err(_) => Box::new(dereference::<Person>(apub_id, context, recursion_counter).await?),
|
||||
Err(_) => {
|
||||
let person_id: ObjectId<Person> = ObjectId::<Person>::new(apub_id);
|
||||
let person: Person = person_id.dereference(context, recursion_counter).await?;
|
||||
Box::new(person)
|
||||
}
|
||||
};
|
||||
Ok(actor)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
use crate::{fetcher::should_refetch_actor, objects::FromApub, APUB_JSON_CONTENT_TYPE};
|
||||
use anyhow::anyhow;
|
||||
use diesel::NotFound;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_db_queries::{ApubObject, DbPool};
|
||||
use lemmy_db_schema::DbUrl;
|
||||
use lemmy_utils::{request::retry, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use log::debug;
|
||||
use reqwest::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
marker::PhantomData,
|
||||
time::Duration,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
/// Maximum number of HTTP requests allowed to handle a single incoming activity (or a single object
|
||||
/// fetch through the search). This should be configurable.
|
||||
static REQUEST_LIMIT: i32 = 25;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||
pub struct ObjectId<Kind>(Url, #[serde(skip)] PhantomData<Kind>)
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de2> <Kind as FromApub>::ApubType: serde::Deserialize<'de2>;
|
||||
|
||||
impl<Kind> ObjectId<Kind>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
pub fn new<K, T>(url: T) -> ObjectId<K>
|
||||
where
|
||||
T: Into<Url>,
|
||||
K: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <K as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
ObjectId(url.into(), PhantomData::<K>)
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &Url {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Fetches an activitypub object, either from local database (if possible), or over http.
|
||||
pub(crate) async fn dereference(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Kind, LemmyError> {
|
||||
let db_object = self.dereference_locally(context.pool()).await?;
|
||||
// if its a local object, only fetch it from the database and not over http
|
||||
if self.0.domain() == Some(&Settings::get().get_hostname_without_port()?) {
|
||||
return match db_object {
|
||||
None => Err(NotFound {}.into()),
|
||||
Some(o) => Ok(o),
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(object) = db_object {
|
||||
if let Some(last_refreshed_at) = object.last_refreshed_at() {
|
||||
// TODO: rename to should_refetch_object()
|
||||
if should_refetch_actor(last_refreshed_at) {
|
||||
debug!("Refetching remote object {}", self.0.as_str());
|
||||
return self.dereference_remotely(context, request_counter).await;
|
||||
}
|
||||
}
|
||||
Ok(object)
|
||||
} else {
|
||||
debug!("Fetching remote object {}", self.0.as_str());
|
||||
self.dereference_remotely(context, request_counter).await
|
||||
}
|
||||
}
|
||||
|
||||
/// returning none means the object was not found in local db
|
||||
async fn dereference_locally(&self, pool: &DbPool) -> Result<Option<Kind>, LemmyError> {
|
||||
let id: DbUrl = self.0.clone().into();
|
||||
let object = blocking(pool, move |conn| ApubObject::read_from_apub_id(conn, &id)).await?;
|
||||
match object {
|
||||
Ok(o) => Ok(Some(o)),
|
||||
Err(NotFound {}) => Ok(None),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn dereference_remotely(
|
||||
&self,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Kind, LemmyError> {
|
||||
// dont fetch local objects this way
|
||||
debug_assert!(self.0.domain() != Some(&Settings::get().hostname));
|
||||
|
||||
*request_counter += 1;
|
||||
if *request_counter > REQUEST_LIMIT {
|
||||
return Err(LemmyError::from(anyhow!("Request limit reached")));
|
||||
}
|
||||
|
||||
let res = retry(|| {
|
||||
context
|
||||
.client()
|
||||
.get(self.0.as_str())
|
||||
.header("Accept", APUB_JSON_CONTENT_TYPE)
|
||||
.timeout(Duration::from_secs(60))
|
||||
.send()
|
||||
})
|
||||
.await?;
|
||||
|
||||
if res.status() == StatusCode::GONE {
|
||||
self.mark_object_deleted(context).await?;
|
||||
return Err(
|
||||
anyhow!(
|
||||
"Fetched remote object {} which was deleted",
|
||||
self.0.as_str()
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
let res2: Kind::ApubType = res.json().await?;
|
||||
|
||||
Ok(Kind::from_apub(&res2, context, self.inner(), request_counter).await?)
|
||||
}
|
||||
|
||||
async fn mark_object_deleted(&self, _context: &LemmyContext) -> Result<(), LemmyError> {
|
||||
// TODO: need to move methods update_deleted, update_removed etc into a trait to use them here.
|
||||
// also, how do we know if the object was deleted vs removed?
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Kind> Display for ObjectId<Kind>
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Kind> From<ObjectId<Kind>> for Url
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
fn from(id: ObjectId<Kind>) -> Self {
|
||||
id.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<Kind> From<ObjectId<Kind>> for DbUrl
|
||||
where
|
||||
Kind: FromApub + ApubObject + Send + 'static,
|
||||
for<'de> <Kind as FromApub>::ApubType: serde::Deserialize<'de>,
|
||||
{
|
||||
fn from(id: ObjectId<Kind>) -> Self {
|
||||
id.0.into()
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ use lemmy_websocket::LemmyContext;
|
|||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PostOrComment {
|
||||
Comment(Box<Comment>),
|
||||
Post(Box<Post>),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
fetcher::{dereference_object_id::dereference, fetch::fetch_remote_object, is_deleted},
|
||||
fetcher::{fetch::fetch_remote_object, is_deleted, object_id::ObjectId},
|
||||
find_object_by_id,
|
||||
objects::{comment::Note, community::Group, person::Person as ApubPerson, post::Page, FromApub},
|
||||
Object,
|
||||
|
@ -124,9 +124,9 @@ async fn build_response(
|
|||
use ResolveObjectResponse as ROR;
|
||||
Ok(match fetch_response {
|
||||
SearchAcceptedObjects::Person(p) => {
|
||||
let person_uri = p.id(&query_url)?;
|
||||
let person_uri: ObjectId<Person> = ObjectId::<Person>::new(p.id(&query_url)?.clone());
|
||||
|
||||
let person = dereference::<Person>(person_uri, context, recursion_counter).await?;
|
||||
let person = person_uri.dereference(context, recursion_counter).await?;
|
||||
ROR {
|
||||
person: blocking(context.pool(), move |conn| {
|
||||
PersonViewSafe::read(conn, person.id)
|
||||
|
@ -137,8 +137,11 @@ async fn build_response(
|
|||
}
|
||||
}
|
||||
SearchAcceptedObjects::Group(g) => {
|
||||
let community_uri = g.id(&query_url)?;
|
||||
let community = dereference::<Community>(community_uri, context, recursion_counter).await?;
|
||||
let community_uri: ObjectId<Community> =
|
||||
ObjectId::<Community>::new(g.id(&query_url)?.clone());
|
||||
let community = community_uri
|
||||
.dereference(context, recursion_counter)
|
||||
.await?;
|
||||
ROR {
|
||||
community: blocking(context.pool(), move |conn| {
|
||||
CommunityView::read(conn, community.id, None)
|
||||
|
|
|
@ -90,7 +90,8 @@ where
|
|||
+ 'static,
|
||||
{
|
||||
let request_counter = &mut 0;
|
||||
let actor = get_or_fetch_and_upsert_actor(activity.actor(), context, request_counter).await?;
|
||||
let actor =
|
||||
get_or_fetch_and_upsert_actor(activity.actor().clone(), context, request_counter).await?;
|
||||
verify_signature(&request, &actor.public_key().context(location_info!())?)?;
|
||||
|
||||
// Do nothing if we received the same activity before
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::fetcher::{object_id::ObjectId, post_or_comment::PostOrComment};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
|
@ -13,7 +14,7 @@ use url::Url;
|
|||
#[serde(untagged)]
|
||||
pub enum CommentInReplyToMigration {
|
||||
Old(Vec<Url>),
|
||||
New(Url),
|
||||
New(ObjectId<PostOrComment>),
|
||||
}
|
||||
|
||||
// Another migration we are doing is to handle all deletions and removals using Delete activity.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
activities::verify_person_in_community,
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
migrations::CommentInReplyToMigration,
|
||||
objects::{create_tombstone, FromApub, Source, ToApub},
|
||||
ActorType,
|
||||
|
@ -49,7 +49,7 @@ pub struct Note {
|
|||
context: OneOrMany<AnyBase>,
|
||||
r#type: NoteType,
|
||||
id: Url,
|
||||
pub(crate) attributed_to: Url,
|
||||
pub(crate) attributed_to: ObjectId<Person>,
|
||||
/// Indicates that the object is publicly readable. Unlike [`Post.to`], this one doesn't contain
|
||||
/// the community ID, as it would be incompatible with Pleroma (and we can get the community from
|
||||
/// the post in [`in_reply_to`]).
|
||||
|
@ -82,18 +82,15 @@ impl Note {
|
|||
CommentInReplyToMigration::Old(in_reply_to) => {
|
||||
// This post, or the parent comment might not yet exist on this server yet, fetch them.
|
||||
let post_id = in_reply_to.get(0).context(location_info!())?;
|
||||
let post = Box::pin(dereference::<Post>(post_id, context, request_counter)).await?;
|
||||
let post_id = ObjectId::<Post>::new(post_id.clone());
|
||||
let post = Box::pin(post_id.dereference(context, request_counter)).await?;
|
||||
|
||||
// The 2nd item, if it exists, is the parent comment apub_id
|
||||
// Nested comments will automatically get fetched recursively
|
||||
let parent_id: Option<CommentId> = match in_reply_to.get(1) {
|
||||
Some(parent_comment_uri) => {
|
||||
let parent_comment = Box::pin(dereference::<Comment>(
|
||||
parent_comment_uri,
|
||||
context,
|
||||
request_counter,
|
||||
))
|
||||
.await?;
|
||||
Some(comment_id) => {
|
||||
let comment_id: ObjectId<Comment> = ObjectId::<Comment>::new(comment_id.clone());
|
||||
let parent_comment = Box::pin(comment_id.dereference(context, request_counter)).await?;
|
||||
|
||||
Some(parent_comment.id)
|
||||
}
|
||||
|
@ -103,8 +100,7 @@ impl Note {
|
|||
Ok((post, parent_id))
|
||||
}
|
||||
CommentInReplyToMigration::New(in_reply_to) => {
|
||||
let parent =
|
||||
Box::pin(dereference::<PostOrComment>(in_reply_to, context, request_counter).await?);
|
||||
let parent = Box::pin(in_reply_to.dereference(context, request_counter).await?);
|
||||
match parent.deref() {
|
||||
PostOrComment::Post(p) => {
|
||||
// Workaround because I cant figure ut how to get the post out of the box (and we dont
|
||||
|
@ -138,10 +134,10 @@ impl Note {
|
|||
if post.locked {
|
||||
return Err(anyhow!("Post is locked").into());
|
||||
}
|
||||
verify_domains_match(&self.attributed_to, &self.id)?;
|
||||
verify_domains_match(self.attributed_to.inner(), &self.id)?;
|
||||
verify_person_in_community(
|
||||
&self.attributed_to,
|
||||
&community.actor_id(),
|
||||
&ObjectId::<Community>::new(community.actor_id()),
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
|
@ -175,7 +171,7 @@ impl ToApub for Comment {
|
|||
context: lemmy_context(),
|
||||
r#type: NoteType::Note,
|
||||
id: self.ap_id.to_owned().into_inner(),
|
||||
attributed_to: creator.actor_id.into_inner(),
|
||||
attributed_to: ObjectId::<Person>::new(creator.actor_id),
|
||||
to: PublicUrl::Public,
|
||||
content: self.content.clone(),
|
||||
media_type: MediaTypeHtml::Html,
|
||||
|
@ -216,7 +212,10 @@ impl FromApub for Comment {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<Comment, LemmyError> {
|
||||
let ap_id = Some(note.id(expected_domain)?.clone().into());
|
||||
let creator = dereference::<Person>(¬e.attributed_to, context, request_counter).await?;
|
||||
let creator = note
|
||||
.attributed_to
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
|
||||
if post.locked {
|
||||
return Err(anyhow!("Post is locked").into());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
extensions::{context::lemmy_context, signatures::PublicKey},
|
||||
fetcher::community::{fetch_community_mods, fetch_community_outbox, update_community_mods},
|
||||
fetcher::community::{fetch_community_outbox, update_community_mods},
|
||||
generate_moderators_url,
|
||||
objects::{create_tombstone, FromApub, ImageObject, Source, ToApub},
|
||||
ActorType,
|
||||
|
@ -175,7 +175,6 @@ impl FromApub for Community {
|
|||
expected_domain: &Url,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<Community, LemmyError> {
|
||||
fetch_community_mods(context, group, request_counter).await?;
|
||||
let form = Group::from_apub_to_form(group, expected_domain).await?;
|
||||
|
||||
let community = blocking(context.pool(), move |conn| Community::upsert(conn, &form)).await??;
|
||||
|
|
|
@ -25,7 +25,7 @@ pub(crate) trait ToApub {
|
|||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
pub(crate) trait FromApub {
|
||||
pub trait FromApub {
|
||||
type ApubType;
|
||||
/// Converts an object from ActivityPub type to Lemmy internal type.
|
||||
///
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
activities::{extract_community, verify_person_in_community},
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{create_tombstone, FromApub, ImageObject, Source, ToApub},
|
||||
ActorType,
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ pub struct Page {
|
|||
context: OneOrMany<AnyBase>,
|
||||
r#type: PageType,
|
||||
id: Url,
|
||||
pub(crate) attributed_to: Url,
|
||||
pub(crate) attributed_to: ObjectId<Person>,
|
||||
to: [Url; 2],
|
||||
name: String,
|
||||
content: Option<String>,
|
||||
|
@ -101,10 +101,10 @@ impl Page {
|
|||
let community = extract_community(&self.to, context, request_counter).await?;
|
||||
|
||||
check_slurs(&self.name)?;
|
||||
verify_domains_match(&self.attributed_to, &self.id)?;
|
||||
verify_domains_match(self.attributed_to.inner(), &self.id)?;
|
||||
verify_person_in_community(
|
||||
&self.attributed_to,
|
||||
&community.actor_id(),
|
||||
&ObjectId::<Community>::new(community.actor_id()),
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
|
@ -137,7 +137,7 @@ impl ToApub for Post {
|
|||
context: lemmy_context(),
|
||||
r#type: PageType::Page,
|
||||
id: self.ap_id.clone().into(),
|
||||
attributed_to: creator.actor_id.into(),
|
||||
attributed_to: ObjectId::<Person>::new(creator.actor_id),
|
||||
to: [community.actor_id.into(), public()],
|
||||
name: self.name.clone(),
|
||||
content: self.body.as_ref().map(|b| markdown_to_html(b)),
|
||||
|
@ -183,7 +183,10 @@ impl FromApub for Post {
|
|||
page.id(expected_domain)?
|
||||
};
|
||||
let ap_id = Some(ap_id.clone().into());
|
||||
let creator = dereference::<Person>(&page.attributed_to, context, request_counter).await?;
|
||||
let creator = page
|
||||
.attributed_to
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
let community = extract_community(&page.to, context, request_counter).await?;
|
||||
|
||||
let thumbnail_url: Option<Url> = page.image.clone().map(|i| i.url);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
extensions::context::lemmy_context,
|
||||
fetcher::dereference_object_id::dereference,
|
||||
fetcher::object_id::ObjectId,
|
||||
objects::{create_tombstone, FromApub, Source, ToApub},
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -35,8 +35,8 @@ pub struct Note {
|
|||
context: OneOrMany<AnyBase>,
|
||||
r#type: NoteType,
|
||||
id: Url,
|
||||
pub(crate) attributed_to: Url,
|
||||
to: Url,
|
||||
pub(crate) attributed_to: ObjectId<Person>,
|
||||
to: ObjectId<Person>,
|
||||
content: String,
|
||||
media_type: MediaTypeHtml,
|
||||
source: Source,
|
||||
|
@ -60,8 +60,11 @@ impl Note {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_domains_match(&self.attributed_to, &self.id)?;
|
||||
let person = dereference::<Person>(&self.attributed_to, context, request_counter).await?;
|
||||
verify_domains_match(self.attributed_to.inner(), &self.id)?;
|
||||
let person = self
|
||||
.attributed_to
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
if person.banned {
|
||||
return Err(anyhow!("Person is banned from site").into());
|
||||
}
|
||||
|
@ -84,8 +87,8 @@ impl ToApub for PrivateMessage {
|
|||
context: lemmy_context(),
|
||||
r#type: NoteType::Note,
|
||||
id: self.ap_id.clone().into(),
|
||||
attributed_to: creator.actor_id.into_inner(),
|
||||
to: recipient.actor_id.into(),
|
||||
attributed_to: ObjectId::<Person>::new(creator.actor_id),
|
||||
to: ObjectId::<Person>::new(recipient.actor_id),
|
||||
content: self.content.clone(),
|
||||
media_type: MediaTypeHtml::Html,
|
||||
source: Source {
|
||||
|
@ -120,8 +123,11 @@ impl FromApub for PrivateMessage {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<PrivateMessage, LemmyError> {
|
||||
let ap_id = Some(note.id(expected_domain)?.clone().into());
|
||||
let creator = dereference::<Person>(¬e.attributed_to, context, request_counter).await?;
|
||||
let recipient = dereference::<Person>(¬e.to, context, request_counter).await?;
|
||||
let creator = note
|
||||
.attributed_to
|
||||
.dereference(context, request_counter)
|
||||
.await?;
|
||||
let recipient = note.to.dereference(context, request_counter).await?;
|
||||
|
||||
let form = PrivateMessageForm {
|
||||
creator_id: creator.id,
|
||||
|
|
|
@ -145,14 +145,14 @@ pub fn derive_activity_fields(input: proc_macro::TokenStream) -> proc_macro::Tok
|
|||
unimplemented!()
|
||||
};
|
||||
let cc_impl = if has_cc {
|
||||
quote! {self.cc.clone().into()}
|
||||
quote! {self.cc.iter().map(|i| i.clone().into()).collect()}
|
||||
} else {
|
||||
quote! {vec![]}
|
||||
};
|
||||
quote! {
|
||||
impl #impl_generics lemmy_apub_lib::ActivityFields for #name #ty_generics #where_clause {
|
||||
fn id_unchecked(&self) -> &url::Url { &self.id }
|
||||
fn actor(&self) -> &url::Url { &self.actor }
|
||||
fn actor(&self) -> &url::Url { &self.actor.inner() }
|
||||
fn cc(&self) -> Vec<url::Url> { #cc_impl }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue