mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-01-11 20:45:53 +00:00
Rewrite delete activities
This commit is contained in:
parent
e65897a350
commit
bc6294a834
16 changed files with 501 additions and 721 deletions
|
@ -8,9 +8,9 @@ use lemmy_api_common::{
|
||||||
is_mod_or_admin,
|
is_mod_or_admin,
|
||||||
send_local_notifs,
|
send_local_notifs,
|
||||||
};
|
};
|
||||||
use lemmy_apub::ApubObjectType;
|
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
|
||||||
use lemmy_db_queries::{source::comment::Comment_, Crud, DeleteableOrRemoveable};
|
use lemmy_db_queries::{source::comment::Comment_, Crud, DeleteableOrRemoveable};
|
||||||
use lemmy_db_schema::source::{comment::*, moderator::*};
|
use lemmy_db_schema::source::{comment::*, community::Community, moderator::*};
|
||||||
use lemmy_db_views::comment_view::CommentView;
|
use lemmy_db_views::comment_view::CommentView;
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperationCrud};
|
||||||
|
@ -47,23 +47,25 @@ impl PerformCrud for DeleteComment {
|
||||||
|
|
||||||
// Do the delete
|
// Do the delete
|
||||||
let deleted = data.deleted;
|
let deleted = data.deleted;
|
||||||
let mut updated_comment = blocking(context.pool(), move |conn| {
|
let updated_comment = blocking(context.pool(), move |conn| {
|
||||||
Comment::update_deleted(conn, comment_id, deleted)
|
Comment::update_deleted(conn, comment_id, deleted)
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
.map_err(|_| ApiError::err("couldnt_update_comment"))?;
|
.map_err(|_| ApiError::err("couldnt_update_comment"))?;
|
||||||
|
|
||||||
// Send the apub message
|
// Send the apub message
|
||||||
if deleted {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
updated_comment = updated_comment.blank_out_deleted_or_removed_info();
|
Community::read(conn, orig_comment.post.community_id)
|
||||||
updated_comment
|
})
|
||||||
.send_delete(&local_user_view.person, context)
|
.await??;
|
||||||
|
send_apub_delete(
|
||||||
|
&local_user_view.person,
|
||||||
|
&community,
|
||||||
|
updated_comment.ap_id.clone().into(),
|
||||||
|
deleted,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_comment
|
|
||||||
.send_undo_delete(&local_user_view.person, context)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refetch it
|
// Refetch it
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
|
@ -142,7 +144,7 @@ impl PerformCrud for RemoveComment {
|
||||||
|
|
||||||
// Do the remove
|
// Do the remove
|
||||||
let removed = data.removed;
|
let removed = data.removed;
|
||||||
let mut updated_comment = blocking(context.pool(), move |conn| {
|
let updated_comment = blocking(context.pool(), move |conn| {
|
||||||
Comment::update_removed(conn, comment_id, removed)
|
Comment::update_removed(conn, comment_id, removed)
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
|
@ -161,16 +163,19 @@ impl PerformCrud for RemoveComment {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Send the apub message
|
// Send the apub message
|
||||||
if removed {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
updated_comment = updated_comment.blank_out_deleted_or_removed_info();
|
Community::read(conn, orig_comment.post.community_id)
|
||||||
updated_comment
|
})
|
||||||
.send_remove(&local_user_view.person, context)
|
.await??;
|
||||||
|
send_apub_remove(
|
||||||
|
&local_user_view.person,
|
||||||
|
&community,
|
||||||
|
updated_comment.ap_id.clone().into(),
|
||||||
|
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||||
|
removed,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_comment
|
|
||||||
.send_undo_remove(&local_user_view.person, context)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refetch it
|
// Refetch it
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{community::send_community_websocket, PerformCrud};
|
use crate::{community::send_community_websocket, PerformCrud};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
|
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
|
||||||
use lemmy_apub::CommunityType;
|
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
|
||||||
use lemmy_db_queries::{source::community::Community_, Crud, DeleteableOrRemoveable};
|
use lemmy_db_queries::{source::community::Community_, Crud, DeleteableOrRemoveable};
|
||||||
use lemmy_db_schema::source::{
|
use lemmy_db_schema::source::{
|
||||||
community::*,
|
community::*,
|
||||||
|
@ -48,16 +48,14 @@ impl PerformCrud for DeleteCommunity {
|
||||||
.map_err(|_| ApiError::err("couldnt_update_community"))?;
|
.map_err(|_| ApiError::err("couldnt_update_community"))?;
|
||||||
|
|
||||||
// Send apub messages
|
// Send apub messages
|
||||||
if deleted {
|
send_apub_delete(
|
||||||
updated_community
|
&local_user_view.person,
|
||||||
.blank_out_deleted_or_removed_info()
|
&updated_community,
|
||||||
.send_delete(local_user_view.person.to_owned(), context)
|
updated_community.actor_id.clone().into(),
|
||||||
|
deleted,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_community
|
|
||||||
.send_undo_delete(local_user_view.person.to_owned(), context)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
@ -123,14 +121,15 @@ impl PerformCrud for RemoveCommunity {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Apub messages
|
// Apub messages
|
||||||
if removed {
|
send_apub_remove(
|
||||||
updated_community
|
&local_user_view.person,
|
||||||
.blank_out_deleted_or_removed_info()
|
&updated_community,
|
||||||
.send_remove(context)
|
updated_community.actor_id.clone().into(),
|
||||||
|
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||||
|
removed,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_community.send_undo_remove(context).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
|
@ -7,9 +7,9 @@ use lemmy_api_common::{
|
||||||
is_mod_or_admin,
|
is_mod_or_admin,
|
||||||
post::*,
|
post::*,
|
||||||
};
|
};
|
||||||
use lemmy_apub::ApubObjectType;
|
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
|
||||||
use lemmy_db_queries::{source::post::Post_, Crud, DeleteableOrRemoveable};
|
use lemmy_db_queries::{source::post::Post_, Crud, DeleteableOrRemoveable};
|
||||||
use lemmy_db_schema::source::{moderator::*, post::*};
|
use lemmy_db_schema::source::{community::Community, moderator::*, post::*};
|
||||||
use lemmy_db_views::post_view::PostView;
|
use lemmy_db_views::post_view::PostView;
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperationCrud};
|
||||||
|
@ -50,16 +50,18 @@ impl PerformCrud for DeletePost {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// apub updates
|
// apub updates
|
||||||
if deleted {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
updated_post
|
Community::read(conn, orig_post.community_id)
|
||||||
.blank_out_deleted_or_removed_info()
|
})
|
||||||
.send_delete(&local_user_view.person, context)
|
.await??;
|
||||||
|
send_apub_delete(
|
||||||
|
&local_user_view.person,
|
||||||
|
&community,
|
||||||
|
updated_post.ap_id.into(),
|
||||||
|
deleted,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_post
|
|
||||||
.send_undo_delete(&local_user_view.person, context)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refetch the post
|
// Refetch the post
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
|
@ -135,16 +137,19 @@ impl PerformCrud for RemovePost {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// apub updates
|
// apub updates
|
||||||
if removed {
|
let community = blocking(context.pool(), move |conn| {
|
||||||
updated_post
|
Community::read(conn, orig_post.community_id)
|
||||||
.blank_out_deleted_or_removed_info()
|
})
|
||||||
.send_remove(&local_user_view.person, context)
|
.await??;
|
||||||
|
send_apub_remove(
|
||||||
|
&local_user_view.person,
|
||||||
|
&community,
|
||||||
|
updated_post.ap_id.into(),
|
||||||
|
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||||
|
removed,
|
||||||
|
context,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
|
||||||
updated_post
|
|
||||||
.send_undo_remove(&local_user_view.person, context)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refetch the post
|
// Refetch the post
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
|
|
|
@ -7,16 +7,10 @@ use crate::{
|
||||||
list_community_follower_inboxes,
|
list_community_follower_inboxes,
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
undo_block_user::UndoBlockUserFromCommunity,
|
||||||
},
|
},
|
||||||
deletion::{
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
delete::DeletePostCommentOrCommunity,
|
|
||||||
undo_delete::UndoDeletePostCommentOrCommunity,
|
|
||||||
},
|
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
post::create_or_update::CreateOrUpdatePost,
|
post::create_or_update::CreateOrUpdatePost,
|
||||||
removal::{
|
removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
|
||||||
remove::RemovePostCommentCommunityOrMod,
|
|
||||||
undo_remove::UndoRemovePostCommentOrCommunity,
|
|
||||||
},
|
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_community,
|
verify_community,
|
||||||
voting::{undo_vote::UndoVote, vote::Vote},
|
voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
|
@ -43,13 +37,13 @@ pub enum AnnouncableActivities {
|
||||||
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
||||||
Vote(Vote),
|
Vote(Vote),
|
||||||
UndoVote(UndoVote),
|
UndoVote(UndoVote),
|
||||||
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
|
Delete(Delete),
|
||||||
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
|
UndoDelete(UndoDelete),
|
||||||
RemovePostCommentCommunityOrMod(RemovePostCommentCommunityOrMod),
|
|
||||||
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
||||||
BlockUserFromCommunity(BlockUserFromCommunity),
|
BlockUserFromCommunity(BlockUserFromCommunity),
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
||||||
AddMod(AddMod),
|
AddMod(AddMod),
|
||||||
|
RemoveMod(RemoveMod),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
|
|
@ -1,19 +1,42 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
comment::send_websocket_message as send_comment_message,
|
comment::send_websocket_message as send_comment_message,
|
||||||
community::send_websocket_message as send_community_message,
|
community::{
|
||||||
deletion::{verify_delete_activity, DeletableObjects},
|
announce::AnnouncableActivities,
|
||||||
|
send_websocket_message as send_community_message,
|
||||||
|
},
|
||||||
|
deletion::{send_apub_delete, verify_delete_activity, DeletableObjects},
|
||||||
|
generate_activity_id,
|
||||||
post::send_websocket_message as send_post_message,
|
post::send_websocket_message as send_post_message,
|
||||||
verify_activity,
|
verify_activity,
|
||||||
},
|
},
|
||||||
|
activity_queue::send_to_community_new,
|
||||||
|
extensions::context::lemmy_context,
|
||||||
fetcher::person::get_or_fetch_and_upsert_person,
|
fetcher::person::get_or_fetch_and_upsert_person,
|
||||||
CommunityType,
|
ActorType,
|
||||||
};
|
};
|
||||||
use activitystreams::activity::kind::DeleteType;
|
use activitystreams::activity::kind::DeleteType;
|
||||||
|
use anyhow::anyhow;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
||||||
use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
|
use lemmy_db_queries::{
|
||||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
source::{comment::Comment_, community::Community_, post::Post_},
|
||||||
|
Crud,
|
||||||
|
};
|
||||||
|
use lemmy_db_schema::source::{
|
||||||
|
comment::Comment,
|
||||||
|
community::Community,
|
||||||
|
moderator::{
|
||||||
|
ModRemoveComment,
|
||||||
|
ModRemoveCommentForm,
|
||||||
|
ModRemoveCommunity,
|
||||||
|
ModRemoveCommunityForm,
|
||||||
|
ModRemovePost,
|
||||||
|
ModRemovePostForm,
|
||||||
|
},
|
||||||
|
person::Person,
|
||||||
|
post::Post,
|
||||||
|
};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -28,18 +51,21 @@ use url::Url;
|
||||||
/// wrapping it in an announce just like other activities, instead of having the community send it.
|
/// wrapping it in an announce just like other activities, instead of having the community send it.
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DeletePostCommentOrCommunity {
|
pub struct Delete {
|
||||||
to: PublicUrl,
|
pub(in crate::activities::deletion) to: PublicUrl,
|
||||||
pub(in crate::activities::deletion) object: Url,
|
pub(in crate::activities::deletion) object: Url,
|
||||||
cc: [Url; 1],
|
pub(in crate::activities::deletion) cc: [Url; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: DeleteType,
|
pub(in crate::activities::deletion) kind: DeleteType,
|
||||||
|
/// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
|
||||||
|
/// deleting their own content.
|
||||||
|
pub(in crate::activities::deletion) summary: Option<String>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
common: ActivityCommonFields,
|
pub(in crate::activities::deletion) common: ActivityCommonFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ActivityHandler for DeletePostCommentOrCommunity {
|
impl ActivityHandler for Delete {
|
||||||
async fn verify(
|
async fn verify(
|
||||||
&self,
|
&self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
|
@ -50,6 +76,7 @@ impl ActivityHandler for DeletePostCommentOrCommunity {
|
||||||
&self.object,
|
&self.object,
|
||||||
&self.cc[0],
|
&self.cc[0],
|
||||||
&self.common,
|
&self.common,
|
||||||
|
self.summary.is_some(),
|
||||||
context,
|
context,
|
||||||
request_counter,
|
request_counter,
|
||||||
)
|
)
|
||||||
|
@ -61,6 +88,59 @@ impl ActivityHandler for DeletePostCommentOrCommunity {
|
||||||
self,
|
self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
if let Some(reason) = self.summary {
|
||||||
|
receive_remove_action(
|
||||||
|
&self.common.actor,
|
||||||
|
&self.object,
|
||||||
|
Some(reason),
|
||||||
|
context,
|
||||||
|
request_counter,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
self.receive_delete_action(context, request_counter).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn common(&self) -> &ActivityCommonFields {
|
||||||
|
&self.common
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Delete {
|
||||||
|
pub(in crate::activities::deletion) async fn send(
|
||||||
|
actor: &Person,
|
||||||
|
community: &Community,
|
||||||
|
object_id: Url,
|
||||||
|
summary: Option<String>,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let id = generate_activity_id(DeleteType::Delete)?;
|
||||||
|
let delete = Delete {
|
||||||
|
to: PublicUrl::Public,
|
||||||
|
object: object_id,
|
||||||
|
cc: [community.actor_id()],
|
||||||
|
kind: DeleteType::Delete,
|
||||||
|
summary,
|
||||||
|
common: ActivityCommonFields {
|
||||||
|
context: lemmy_context(),
|
||||||
|
id: id.clone(),
|
||||||
|
actor: actor.actor_id(),
|
||||||
|
unparsed: Default::default(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let activity = AnnouncableActivities::Delete(delete);
|
||||||
|
send_to_community_new(activity, &id, actor, community, vec![], context).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: would be nice if we could merge this and receive_delete_action() into a single method
|
||||||
|
// (or merge with receive_undo_delete_action() instead)
|
||||||
|
async fn receive_delete_action(
|
||||||
|
&self,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
use UserOperationCrud::*;
|
use UserOperationCrud::*;
|
||||||
match DeletableObjects::read_from_db(&self.object, context).await? {
|
match DeletableObjects::read_from_db(&self.object, context).await? {
|
||||||
|
@ -68,7 +148,8 @@ impl ActivityHandler for DeletePostCommentOrCommunity {
|
||||||
if community.local {
|
if community.local {
|
||||||
let mod_ =
|
let mod_ =
|
||||||
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
|
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
|
||||||
community.send_delete(mod_, context).await?;
|
let object = community.actor_id();
|
||||||
|
send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let deleted_community = blocking(context.pool(), move |conn| {
|
let deleted_community = blocking(context.pool(), move |conn| {
|
||||||
|
@ -82,19 +163,85 @@ impl ActivityHandler for DeletePostCommentOrCommunity {
|
||||||
Post::update_deleted(conn, post.id, true)
|
Post::update_deleted(conn, post.id, true)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
send_post_message(deleted_post.id, EditPost, context).await
|
send_post_message(deleted_post.id, DeletePost, context).await
|
||||||
}
|
}
|
||||||
DeletableObjects::Comment(comment) => {
|
DeletableObjects::Comment(comment) => {
|
||||||
let deleted_comment = blocking(context.pool(), move |conn| {
|
let deleted_comment = blocking(context.pool(), move |conn| {
|
||||||
Comment::update_deleted(conn, comment.id, true)
|
Comment::update_deleted(conn, comment.id, true)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
send_comment_message(deleted_comment.id, vec![], EditComment, context).await
|
send_comment_message(deleted_comment.id, vec![], DeleteComment, context).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common(&self) -> &ActivityCommonFields {
|
// TODO: reason is optional for compat with v0.11, make it mandatory after removing the migration
|
||||||
&self.common
|
pub(in crate::activities) async fn receive_remove_action(
|
||||||
|
actor: &Url,
|
||||||
|
object: &Url,
|
||||||
|
reason: Option<String>,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let actor = get_or_fetch_and_upsert_person(actor, context, request_counter).await?;
|
||||||
|
use UserOperationCrud::*;
|
||||||
|
match DeletableObjects::read_from_db(object, context).await? {
|
||||||
|
DeletableObjects::Community(community) => {
|
||||||
|
if community.local {
|
||||||
|
return Err(anyhow!("Only local admin can remove community").into());
|
||||||
|
}
|
||||||
|
let form = ModRemoveCommunityForm {
|
||||||
|
mod_person_id: actor.id,
|
||||||
|
community_id: community.id,
|
||||||
|
removed: Some(true),
|
||||||
|
reason,
|
||||||
|
expires: None,
|
||||||
|
};
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
ModRemoveCommunity::create(conn, &form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
let deleted_community = blocking(context.pool(), move |conn| {
|
||||||
|
Community::update_removed(conn, community.id, true)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
send_community_message(deleted_community.id, RemoveCommunity, context).await
|
||||||
|
}
|
||||||
|
DeletableObjects::Post(post) => {
|
||||||
|
let form = ModRemovePostForm {
|
||||||
|
mod_person_id: actor.id,
|
||||||
|
post_id: post.id,
|
||||||
|
removed: Some(true),
|
||||||
|
reason,
|
||||||
|
};
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
ModRemovePost::create(conn, &form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
let removed_post = blocking(context.pool(), move |conn| {
|
||||||
|
Post::update_removed(conn, post.id, true)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
send_post_message(removed_post.id, RemovePost, context).await
|
||||||
|
}
|
||||||
|
DeletableObjects::Comment(comment) => {
|
||||||
|
let form = ModRemoveCommentForm {
|
||||||
|
mod_person_id: actor.id,
|
||||||
|
comment_id: comment.id,
|
||||||
|
removed: Some(true),
|
||||||
|
reason,
|
||||||
|
};
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
ModRemoveComment::create(conn, &form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
let removed_comment = blocking(context.pool(), move |conn| {
|
||||||
|
Comment::update_removed(conn, comment.id, true)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
send_comment_message(removed_comment.id, vec![], RemoveComment, context).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{verify_mod_action, verify_person_in_community},
|
activities::{
|
||||||
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
|
verify_mod_action,
|
||||||
|
verify_person_in_community,
|
||||||
|
},
|
||||||
ActorType,
|
ActorType,
|
||||||
};
|
};
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields};
|
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields};
|
||||||
use lemmy_db_queries::ApubObject;
|
use lemmy_db_queries::ApubObject;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{comment::Comment, community::Community, post::Post},
|
source::{comment::Comment, community::Community, person::Person, post::Post},
|
||||||
DbUrl,
|
DbUrl,
|
||||||
};
|
};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
|
@ -16,6 +20,37 @@ use url::Url;
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod undo_delete;
|
pub mod undo_delete;
|
||||||
|
|
||||||
|
pub async fn send_apub_delete(
|
||||||
|
actor: &Person,
|
||||||
|
community: &Community,
|
||||||
|
object_id: Url,
|
||||||
|
deleted: bool,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
if deleted {
|
||||||
|
Delete::send(actor, community, object_id, None, context).await
|
||||||
|
} else {
|
||||||
|
UndoDelete::send(actor, community, object_id, None, context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its
|
||||||
|
// ugly
|
||||||
|
pub async fn send_apub_remove(
|
||||||
|
actor: &Person,
|
||||||
|
community: &Community,
|
||||||
|
object_id: Url,
|
||||||
|
reason: String,
|
||||||
|
removed: bool,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
if removed {
|
||||||
|
Delete::send(actor, community, object_id, Some(reason), context).await
|
||||||
|
} else {
|
||||||
|
UndoDelete::send(actor, community, object_id, Some(reason), context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum DeletableObjects {
|
pub enum DeletableObjects {
|
||||||
Community(Box<Community>),
|
Community(Box<Community>),
|
||||||
Comment(Box<Comment>),
|
Comment(Box<Comment>),
|
||||||
|
@ -53,10 +88,11 @@ impl DeletableObjects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::activities::deletion) async fn verify_delete_activity(
|
pub(in crate::activities) async fn verify_delete_activity(
|
||||||
object: &Url,
|
object: &Url,
|
||||||
cc: &Url,
|
cc: &Url,
|
||||||
common: &ActivityCommonFields,
|
common: &ActivityCommonFields,
|
||||||
|
is_mod_action: bool,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
|
@ -68,17 +104,49 @@ pub(in crate::activities::deletion) async fn verify_delete_activity(
|
||||||
// deleted community (which fails)
|
// deleted community (which fails)
|
||||||
verify_person_in_community(&common.actor, cc, context, request_counter).await?;
|
verify_person_in_community(&common.actor, cc, context, request_counter).await?;
|
||||||
}
|
}
|
||||||
|
// community deletion is always a mod (or admin) action
|
||||||
verify_mod_action(&common.actor, c.actor_id(), context).await?;
|
verify_mod_action(&common.actor, c.actor_id(), context).await?;
|
||||||
}
|
}
|
||||||
DeletableObjects::Post(p) => {
|
DeletableObjects::Post(p) => {
|
||||||
verify_person_in_community(&common.actor, cc, context, request_counter).await?;
|
verify_delete_activity_post_or_comment(
|
||||||
// domain of post ap_id and post.creator ap_id are identical, so we just check the former
|
cc,
|
||||||
verify_domains_match(&common.actor, &p.ap_id.into())?;
|
common,
|
||||||
|
&p.ap_id.into(),
|
||||||
|
is_mod_action,
|
||||||
|
context,
|
||||||
|
request_counter,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
DeletableObjects::Comment(c) => {
|
DeletableObjects::Comment(c) => {
|
||||||
verify_person_in_community(&common.actor, cc, context, request_counter).await?;
|
verify_delete_activity_post_or_comment(
|
||||||
verify_domains_match(&common.actor, &c.ap_id.into())?;
|
cc,
|
||||||
|
common,
|
||||||
|
&c.ap_id.into(),
|
||||||
|
is_mod_action,
|
||||||
|
context,
|
||||||
|
request_counter,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn verify_delete_activity_post_or_comment(
|
||||||
|
cc: &Url,
|
||||||
|
common: &ActivityCommonFields,
|
||||||
|
object_id: &Url,
|
||||||
|
is_mod_action: bool,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
verify_person_in_community(&common.actor, cc, context, request_counter).await?;
|
||||||
|
if is_mod_action {
|
||||||
|
verify_mod_action(&common.actor, cc.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(&common.actor, object_id)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,28 +1,35 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
comment::send_websocket_message as send_comment_message,
|
comment::send_websocket_message as send_comment_message,
|
||||||
community::send_websocket_message as send_community_message,
|
community::{
|
||||||
deletion::{delete::DeletePostCommentOrCommunity, verify_delete_activity, DeletableObjects},
|
announce::AnnouncableActivities,
|
||||||
|
send_websocket_message as send_community_message,
|
||||||
|
},
|
||||||
|
deletion::{delete::Delete, send_apub_delete, verify_delete_activity, DeletableObjects},
|
||||||
|
generate_activity_id,
|
||||||
post::send_websocket_message as send_post_message,
|
post::send_websocket_message as send_post_message,
|
||||||
verify_activity,
|
verify_activity,
|
||||||
},
|
},
|
||||||
|
activity_queue::send_to_community_new,
|
||||||
|
extensions::context::lemmy_context,
|
||||||
fetcher::person::get_or_fetch_and_upsert_person,
|
fetcher::person::get_or_fetch_and_upsert_person,
|
||||||
CommunityType,
|
ActorType,
|
||||||
};
|
};
|
||||||
use activitystreams::activity::kind::UndoType;
|
use activitystreams::activity::kind::{DeleteType, UndoType};
|
||||||
|
use anyhow::anyhow;
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
||||||
use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
|
use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
|
||||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoDeletePostCommentOrCommunity {
|
pub struct UndoDelete {
|
||||||
to: PublicUrl,
|
to: PublicUrl,
|
||||||
object: DeletePostCommentOrCommunity,
|
object: Delete,
|
||||||
cc: [Url; 1],
|
cc: [Url; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: UndoType,
|
kind: UndoType,
|
||||||
|
@ -31,7 +38,7 @@ pub struct UndoDeletePostCommentOrCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ActivityHandler for UndoDeletePostCommentOrCommunity {
|
impl ActivityHandler for UndoDelete {
|
||||||
async fn verify(
|
async fn verify(
|
||||||
&self,
|
&self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
|
@ -43,6 +50,7 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity {
|
||||||
&self.object.object,
|
&self.object.object,
|
||||||
&self.cc[0],
|
&self.cc[0],
|
||||||
&self.common,
|
&self.common,
|
||||||
|
self.object.summary.is_some(),
|
||||||
context,
|
context,
|
||||||
request_counter,
|
request_counter,
|
||||||
)
|
)
|
||||||
|
@ -54,6 +62,64 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity {
|
||||||
self,
|
self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
if self.object.summary.is_some() {
|
||||||
|
UndoDelete::receive_undo_remove_action(&self.object.object, context).await
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.receive_undo_delete_action(context, request_counter)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn common(&self) -> &ActivityCommonFields {
|
||||||
|
&self.common
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UndoDelete {
|
||||||
|
pub(in crate::activities::deletion) async fn send(
|
||||||
|
actor: &Person,
|
||||||
|
community: &Community,
|
||||||
|
object_id: Url,
|
||||||
|
summary: Option<String>,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let delete = Delete {
|
||||||
|
to: PublicUrl::Public,
|
||||||
|
object: object_id,
|
||||||
|
cc: [community.actor_id()],
|
||||||
|
kind: DeleteType::Delete,
|
||||||
|
summary,
|
||||||
|
common: ActivityCommonFields {
|
||||||
|
context: lemmy_context(),
|
||||||
|
id: generate_activity_id(DeleteType::Delete)?,
|
||||||
|
actor: actor.actor_id(),
|
||||||
|
unparsed: Default::default(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = generate_activity_id(UndoType::Undo)?;
|
||||||
|
let undo = UndoDelete {
|
||||||
|
to: PublicUrl::Public,
|
||||||
|
object: delete,
|
||||||
|
cc: [community.actor_id()],
|
||||||
|
kind: UndoType::Undo,
|
||||||
|
common: ActivityCommonFields {
|
||||||
|
context: lemmy_context(),
|
||||||
|
id: id.clone(),
|
||||||
|
actor: actor.actor_id(),
|
||||||
|
unparsed: Default::default(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let activity = AnnouncableActivities::UndoDelete(undo);
|
||||||
|
send_to_community_new(activity, &id, actor, community, vec![], context).await
|
||||||
|
}
|
||||||
|
async fn receive_undo_delete_action(
|
||||||
|
&self,
|
||||||
|
context: &LemmyContext,
|
||||||
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
use UserOperationCrud::*;
|
use UserOperationCrud::*;
|
||||||
let object = DeletableObjects::read_from_db(&self.object.object, context).await?;
|
let object = DeletableObjects::read_from_db(&self.object.object, context).await?;
|
||||||
|
@ -62,7 +128,14 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity {
|
||||||
if community.local {
|
if community.local {
|
||||||
let mod_ =
|
let mod_ =
|
||||||
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
|
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
|
||||||
community.send_undo_delete(mod_, context).await?;
|
send_apub_delete(
|
||||||
|
&mod_,
|
||||||
|
&community.clone(),
|
||||||
|
community.actor_id(),
|
||||||
|
false,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let deleted_community = blocking(context.pool(), move |conn| {
|
let deleted_community = blocking(context.pool(), move |conn| {
|
||||||
|
@ -88,7 +161,37 @@ impl ActivityHandler for UndoDeletePostCommentOrCommunity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common(&self) -> &ActivityCommonFields {
|
pub(in crate::activities) async fn receive_undo_remove_action(
|
||||||
&self.common
|
object: &Url,
|
||||||
|
context: &LemmyContext,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
use UserOperationCrud::*;
|
||||||
|
match DeletableObjects::read_from_db(object, context).await? {
|
||||||
|
DeletableObjects::Community(community) => {
|
||||||
|
if community.local {
|
||||||
|
return Err(anyhow!("Only local admin can restore community").into());
|
||||||
|
}
|
||||||
|
let deleted_community = blocking(context.pool(), move |conn| {
|
||||||
|
Community::update_removed(conn, community.id, false)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
send_community_message(deleted_community.id, EditCommunity, context).await
|
||||||
|
}
|
||||||
|
DeletableObjects::Post(post) => {
|
||||||
|
let removed_post = blocking(context.pool(), move |conn| {
|
||||||
|
Post::update_removed(conn, post.id, false)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
send_post_message(removed_post.id, EditPost, context).await
|
||||||
|
}
|
||||||
|
DeletableObjects::Comment(comment) => {
|
||||||
|
let removed_comment = blocking(context.pool(), move |conn| {
|
||||||
|
Comment::update_removed(conn, comment.id, false)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
send_comment_message(removed_comment.id, vec![], EditComment, context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +1,59 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
comment::send_websocket_message as send_comment_message,
|
deletion::{delete::receive_remove_action, verify_delete_activity},
|
||||||
community::send_websocket_message as send_community_message,
|
|
||||||
post::send_websocket_message as send_post_message,
|
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_add_remove_moderator_target,
|
verify_add_remove_moderator_target,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
},
|
},
|
||||||
fetcher::{
|
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
|
||||||
community::get_or_fetch_and_upsert_community,
|
|
||||||
objects::get_or_fetch_and_insert_post_or_comment,
|
|
||||||
person::get_or_fetch_and_upsert_person,
|
|
||||||
},
|
|
||||||
CommunityType,
|
CommunityType,
|
||||||
PostOrComment,
|
|
||||||
};
|
};
|
||||||
use activitystreams::{activity::kind::RemoveType, base::AnyBase};
|
use activitystreams::{activity::kind::RemoveType, base::AnyBase};
|
||||||
use anyhow::anyhow;
|
|
||||||
use lemmy_api_common::blocking;
|
use lemmy_api_common::blocking;
|
||||||
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::Joinable;
|
||||||
source::{comment::Comment_, community::Community_, post::Post_},
|
use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm};
|
||||||
Joinable,
|
|
||||||
};
|
|
||||||
use lemmy_db_schema::source::{
|
|
||||||
comment::Comment,
|
|
||||||
community::{Community, CommunityModerator, CommunityModeratorForm},
|
|
||||||
post::Post,
|
|
||||||
};
|
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::LemmyContext;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
// TODO: we can probably deduplicate a bunch of code between this and DeletePostCommentOrCommunity
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RemovePostCommentCommunityOrMod {
|
pub struct RemoveMod {
|
||||||
to: PublicUrl,
|
to: PublicUrl,
|
||||||
pub(in crate::activities::removal) object: Url,
|
pub(in crate::activities::removal) object: Url,
|
||||||
cc: [Url; 1],
|
cc: [Url; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: RemoveType,
|
kind: RemoveType,
|
||||||
// if target is set, this is means remove mod from community
|
// if target is set, this is means remove mod from community
|
||||||
target: Option<Url>,
|
pub(in crate::activities::removal) target: Option<Url>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
common: ActivityCommonFields,
|
common: ActivityCommonFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl ActivityHandler for RemovePostCommentCommunityOrMod {
|
impl ActivityHandler for RemoveMod {
|
||||||
async fn verify(
|
async fn verify(
|
||||||
&self,
|
&self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
verify_activity(self.common())?;
|
verify_activity(self.common())?;
|
||||||
let object_community =
|
if let Some(target) = &self.target {
|
||||||
get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
|
|
||||||
// removing a community
|
|
||||||
if object_community.is_ok() {
|
|
||||||
verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
|
|
||||||
}
|
|
||||||
// removing community mod
|
|
||||||
else if let Some(target) = &self.target {
|
|
||||||
verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
|
verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
|
||||||
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
|
verify_mod_action(&self.common.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].clone())?;
|
||||||
}
|
} else {
|
||||||
// removing a post or comment
|
verify_delete_activity(
|
||||||
else {
|
&self.object,
|
||||||
verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
|
&self.cc[0],
|
||||||
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
|
self.common(),
|
||||||
|
true,
|
||||||
|
context,
|
||||||
|
request_counter,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -81,27 +63,7 @@ impl ActivityHandler for RemovePostCommentCommunityOrMod {
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let object_community =
|
if self.target.is_some() {
|
||||||
get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
|
|
||||||
// removing a community
|
|
||||||
if let Ok(community) = object_community {
|
|
||||||
if community.local {
|
|
||||||
return Err(anyhow!("Only local admin can remove community").into());
|
|
||||||
}
|
|
||||||
let deleted_community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::update_removed(conn, community.id, true)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
send_community_message(
|
|
||||||
deleted_community.id,
|
|
||||||
UserOperationCrud::RemoveCommunity,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
// removing community mod
|
|
||||||
else if self.target.is_some() {
|
|
||||||
let community =
|
let community =
|
||||||
get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter).await?;
|
get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter).await?;
|
||||||
let remove_mod =
|
let remove_mod =
|
||||||
|
@ -121,33 +83,17 @@ impl ActivityHandler for RemovePostCommentCommunityOrMod {
|
||||||
.await?;
|
.await?;
|
||||||
// TODO: send websocket notification about removed mod
|
// TODO: send websocket notification about removed mod
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
} else {
|
||||||
// removing a post or comment
|
receive_remove_action(
|
||||||
else {
|
&self.common.actor,
|
||||||
match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
|
&self.object,
|
||||||
PostOrComment::Post(post) => {
|
None,
|
||||||
let removed_post = blocking(context.pool(), move |conn| {
|
|
||||||
Post::update_removed(conn, post.id, true)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await
|
|
||||||
}
|
|
||||||
PostOrComment::Comment(comment) => {
|
|
||||||
let removed_comment = blocking(context.pool(), move |conn| {
|
|
||||||
Comment::update_removed(conn, comment.id, true)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
send_comment_message(
|
|
||||||
removed_comment.id,
|
|
||||||
vec![],
|
|
||||||
UserOperationCrud::EditComment,
|
|
||||||
context,
|
context,
|
||||||
|
request_counter,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn common(&self) -> &ActivityCommonFields {
|
fn common(&self) -> &ActivityCommonFields {
|
||||||
&self.common
|
&self.common
|
||||||
|
|
|
@ -1,34 +1,20 @@
|
||||||
use crate::{
|
use crate::activities::{
|
||||||
activities::{
|
deletion::{undo_delete::UndoDelete, verify_delete_activity},
|
||||||
comment::send_websocket_message as send_comment_message,
|
removal::remove::RemoveMod,
|
||||||
community::send_websocket_message as send_community_message,
|
|
||||||
post::send_websocket_message as send_post_message,
|
|
||||||
removal::remove::RemovePostCommentCommunityOrMod,
|
|
||||||
verify_activity,
|
verify_activity,
|
||||||
verify_mod_action,
|
|
||||||
verify_person_in_community,
|
|
||||||
},
|
|
||||||
fetcher::{
|
|
||||||
community::get_or_fetch_and_upsert_community,
|
|
||||||
objects::get_or_fetch_and_insert_post_or_comment,
|
|
||||||
},
|
|
||||||
PostOrComment,
|
|
||||||
};
|
};
|
||||||
use activitystreams::activity::kind::UndoType;
|
use activitystreams::activity::kind::UndoType;
|
||||||
use anyhow::anyhow;
|
|
||||||
use lemmy_api_common::blocking;
|
|
||||||
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
use lemmy_apub_lib::{values::PublicUrl, ActivityCommonFields, ActivityHandler};
|
||||||
use lemmy_db_queries::source::{comment::Comment_, community::Community_, post::Post_};
|
|
||||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
|
||||||
use lemmy_utils::LemmyError;
|
use lemmy_utils::LemmyError;
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::LemmyContext;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UndoRemovePostCommentOrCommunity {
|
pub struct UndoRemovePostCommentOrCommunity {
|
||||||
to: PublicUrl,
|
to: PublicUrl,
|
||||||
object: RemovePostCommentCommunityOrMod,
|
// Note, there is no such thing as Undo/Remove/Mod, so we ignore that
|
||||||
|
object: RemoveMod,
|
||||||
cc: [Url; 1],
|
cc: [Url; 1],
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: UndoType,
|
kind: UndoType,
|
||||||
|
@ -44,74 +30,26 @@ impl ActivityHandler for UndoRemovePostCommentOrCommunity {
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
verify_activity(self.common())?;
|
verify_activity(self.common())?;
|
||||||
let object_community =
|
|
||||||
get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
|
|
||||||
// removing a community
|
|
||||||
if object_community.is_ok() {
|
|
||||||
verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
|
|
||||||
}
|
|
||||||
// removing a post or comment
|
|
||||||
else {
|
|
||||||
verify_person_in_community(&self.common.actor, &self.cc[0], context, request_counter).await?;
|
|
||||||
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
|
|
||||||
}
|
|
||||||
self.object.verify(context, request_counter).await?;
|
self.object.verify(context, request_counter).await?;
|
||||||
// dont check that actor and object.actor are identical, so that one mod can
|
|
||||||
// undo the action of another
|
verify_delete_activity(
|
||||||
|
&self.object.object,
|
||||||
|
&self.cc[0],
|
||||||
|
self.common(),
|
||||||
|
true,
|
||||||
|
context,
|
||||||
|
request_counter,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive(
|
async fn receive(
|
||||||
self,
|
self,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
request_counter: &mut i32,
|
_request_counter: &mut i32,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let object_community =
|
UndoDelete::receive_undo_remove_action(&self.object.object, context).await
|
||||||
get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
|
|
||||||
// restoring a community
|
|
||||||
if let Ok(community) = object_community {
|
|
||||||
if community.local {
|
|
||||||
return Err(anyhow!("Only local admin can undo remove community").into());
|
|
||||||
}
|
|
||||||
let deleted_community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::update_removed(conn, community.id, false)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
send_community_message(
|
|
||||||
deleted_community.id,
|
|
||||||
UserOperationCrud::EditCommunity,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
// restoring a post or comment
|
|
||||||
else {
|
|
||||||
match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
PostOrComment::Post(post) => {
|
|
||||||
let removed_post = blocking(context.pool(), move |conn| {
|
|
||||||
Post::update_removed(conn, post.id, false)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
send_post_message(removed_post.id, UserOperationCrud::EditPost, context).await
|
|
||||||
}
|
|
||||||
PostOrComment::Comment(comment) => {
|
|
||||||
let removed_comment = blocking(context.pool(), move |conn| {
|
|
||||||
Comment::update_removed(conn, comment.id, false)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
send_comment_message(
|
|
||||||
removed_comment.id,
|
|
||||||
vec![],
|
|
||||||
UserOperationCrud::EditComment,
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common(&self) -> &ActivityCommonFields {
|
fn common(&self) -> &ActivityCommonFields {
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
use crate::{
|
|
||||||
activities::generate_activity_id,
|
|
||||||
activity_queue::send_to_community,
|
|
||||||
extensions::context::lemmy_context,
|
|
||||||
ActorType,
|
|
||||||
ApubObjectType,
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
|
||||||
activity::{
|
|
||||||
kind::{DeleteType, RemoveType, UndoType},
|
|
||||||
Delete,
|
|
||||||
Remove,
|
|
||||||
Undo,
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
public,
|
|
||||||
};
|
|
||||||
use lemmy_api_common::blocking;
|
|
||||||
use lemmy_db_queries::Crud;
|
|
||||||
use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
|
|
||||||
use lemmy_utils::LemmyError;
|
|
||||||
use lemmy_websocket::LemmyContext;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl ApubObjectType for Comment {
|
|
||||||
async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let post_id = self.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
|
|
||||||
let community_id = post.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut delete = Delete::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(delete, creator, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_undo_delete(
|
|
||||||
&self,
|
|
||||||
creator: &Person,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let post_id = self.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
|
|
||||||
let community_id = post.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
// Generate a fake delete activity, with the correct object
|
|
||||||
let mut delete = Delete::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
// Undo that fake activity
|
|
||||||
let mut undo = Undo::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
delete.into_any_base()?,
|
|
||||||
);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(undo, creator, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let post_id = self.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
|
|
||||||
let community_id = post.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut remove = Remove::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(remove, mod_, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_undo_remove(
|
|
||||||
&self,
|
|
||||||
mod_: &Person,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let post_id = self.post_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
|
|
||||||
|
|
||||||
let community_id = post.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
// Generate a fake delete activity, with the correct object
|
|
||||||
let mut remove = Remove::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
// Undo that fake activity
|
|
||||||
let mut undo = Undo::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
remove.into_any_base()?,
|
|
||||||
);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(undo, mod_, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,20 +12,10 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
activity::{
|
activity::{
|
||||||
kind::{
|
kind::{AddType, AnnounceType, BlockType, RemoveType, UndoType, UpdateType},
|
||||||
AddType,
|
|
||||||
AnnounceType,
|
|
||||||
BlockType,
|
|
||||||
DeleteType,
|
|
||||||
LikeType,
|
|
||||||
RemoveType,
|
|
||||||
UndoType,
|
|
||||||
UpdateType,
|
|
||||||
},
|
|
||||||
Add,
|
Add,
|
||||||
Announce,
|
Announce,
|
||||||
Block,
|
Block,
|
||||||
Delete,
|
|
||||||
OptTargetRefExt,
|
OptTargetRefExt,
|
||||||
Remove,
|
Remove,
|
||||||
Undo,
|
Undo,
|
||||||
|
@ -97,112 +87,6 @@ impl CommunityType for Community {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the creator of a community deletes the community, send this to all followers.
|
|
||||||
///
|
|
||||||
/// We need to handle deletion by a remote mod separately.
|
|
||||||
async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
// Local mod, send directly from community to followers
|
|
||||||
if self.local {
|
|
||||||
let mut delete = Delete::new(self.actor_id(), self.actor_id());
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
send_to_community_followers(delete, self, None, context).await?;
|
|
||||||
}
|
|
||||||
// Remote mod, send from mod to community
|
|
||||||
else {
|
|
||||||
let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(delete, &mod_, self, None, context).await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If the creator of a community reverts the deletion of a community, send this to all followers.
|
|
||||||
///
|
|
||||||
/// We need to handle undelete by a remote mod separately.
|
|
||||||
async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
// Local mod, send directly from community to followers
|
|
||||||
if self.local {
|
|
||||||
let mut delete = Delete::new(self.actor_id(), self.actor_id());
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
send_to_community_followers(undo, self, None, context).await?;
|
|
||||||
}
|
|
||||||
// Remote mod, send from mod to community
|
|
||||||
else {
|
|
||||||
let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.actor_id()]);
|
|
||||||
|
|
||||||
let mut undo = Undo::new(mod_.actor_id(), delete.into_any_base()?);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(undo, &mod_, self, None, context).await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If an admin removes a community, send this to all followers.
|
|
||||||
async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let mut remove = Remove::new(self.actor_id(), self.actor_id());
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
send_to_community_followers(remove, self, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If an admin reverts the removal of a community, send this to all followers.
|
|
||||||
async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let mut remove = Remove::new(self.actor_id(), self.actor_id());
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
// Undo that fake activity
|
|
||||||
let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(LikeType::Like)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![self.followers_url()]);
|
|
||||||
|
|
||||||
send_to_community_followers(undo, self, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wraps an activity sent to the community in an announce, and then sends the announce to all
|
/// Wraps an activity sent to the community in an announce, and then sends the announce to all
|
||||||
/// community followers.
|
/// community followers.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
pub(crate) mod comment;
|
|
||||||
pub(crate) mod community;
|
pub(crate) mod community;
|
||||||
pub(crate) mod person;
|
pub(crate) mod person;
|
||||||
pub(crate) mod post;
|
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
use crate::{
|
|
||||||
activities::generate_activity_id,
|
|
||||||
activity_queue::send_to_community,
|
|
||||||
extensions::context::lemmy_context,
|
|
||||||
ActorType,
|
|
||||||
ApubObjectType,
|
|
||||||
};
|
|
||||||
use activitystreams::{
|
|
||||||
activity::{
|
|
||||||
kind::{DeleteType, RemoveType, UndoType},
|
|
||||||
Delete,
|
|
||||||
Remove,
|
|
||||||
Undo,
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
public,
|
|
||||||
};
|
|
||||||
use lemmy_api_common::blocking;
|
|
||||||
use lemmy_db_queries::Crud;
|
|
||||||
use lemmy_db_schema::source::{community::Community, person::Person, post::Post};
|
|
||||||
use lemmy_utils::LemmyError;
|
|
||||||
use lemmy_websocket::LemmyContext;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl ApubObjectType for Post {
|
|
||||||
async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let community_id = self.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut delete = Delete::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(delete, creator, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_undo_delete(
|
|
||||||
&self,
|
|
||||||
creator: &Person,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let community_id = self.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut delete = Delete::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
delete
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(DeleteType::Delete)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
// Undo that fake activity
|
|
||||||
let mut undo = Undo::new(
|
|
||||||
creator.actor_id.to_owned().into_inner(),
|
|
||||||
delete.into_any_base()?,
|
|
||||||
);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(undo, creator, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> {
|
|
||||||
let community_id = self.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut remove = Remove::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(remove, mod_, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_undo_remove(
|
|
||||||
&self,
|
|
||||||
mod_: &Person,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let community_id = self.community_id;
|
|
||||||
let community = blocking(context.pool(), move |conn| {
|
|
||||||
Community::read(conn, community_id)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let mut remove = Remove::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
self.ap_id.to_owned().into_inner(),
|
|
||||||
);
|
|
||||||
remove
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(RemoveType::Remove)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
// Undo that fake activity
|
|
||||||
let mut undo = Undo::new(
|
|
||||||
mod_.actor_id.to_owned().into_inner(),
|
|
||||||
remove.into_any_base()?,
|
|
||||||
);
|
|
||||||
undo
|
|
||||||
.set_many_contexts(lemmy_context())
|
|
||||||
.set_id(generate_activity_id(UndoType::Undo)?)
|
|
||||||
.set_to(public())
|
|
||||||
.set_many_ccs(vec![community.actor_id()]);
|
|
||||||
|
|
||||||
send_to_community(undo, mod_, &community, None, context).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ use crate::activities::{
|
||||||
undo_block_user::UndoBlockUserFromCommunity,
|
undo_block_user::UndoBlockUserFromCommunity,
|
||||||
update::UpdateCommunity,
|
update::UpdateCommunity,
|
||||||
},
|
},
|
||||||
deletion::{delete::DeletePostCommentOrCommunity, undo_delete::UndoDeletePostCommentOrCommunity},
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity},
|
following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity},
|
||||||
post::create_or_update::CreateOrUpdatePost,
|
post::create_or_update::CreateOrUpdatePost,
|
||||||
private_message::{
|
private_message::{
|
||||||
|
@ -15,10 +15,7 @@ use crate::activities::{
|
||||||
delete::DeletePrivateMessage,
|
delete::DeletePrivateMessage,
|
||||||
undo_delete::UndoDeletePrivateMessage,
|
undo_delete::UndoDeletePrivateMessage,
|
||||||
},
|
},
|
||||||
removal::{
|
removal::{remove::RemoveMod, undo_remove::UndoRemovePostCommentOrCommunity},
|
||||||
remove::RemovePostCommentCommunityOrMod,
|
|
||||||
undo_remove::UndoRemovePostCommentOrCommunity,
|
|
||||||
},
|
|
||||||
voting::{undo_vote::UndoVote, vote::Vote},
|
voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
};
|
};
|
||||||
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
|
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
|
||||||
|
@ -45,14 +42,14 @@ pub enum GroupInboxActivities {
|
||||||
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
||||||
Vote(Vote),
|
Vote(Vote),
|
||||||
UndoVote(UndoVote),
|
UndoVote(UndoVote),
|
||||||
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
|
DeletePostCommentOrCommunity(Delete),
|
||||||
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
|
UndoDeletePostCommentOrCommunity(UndoDelete),
|
||||||
RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod),
|
|
||||||
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
||||||
UpdateCommunity(Box<UpdateCommunity>),
|
UpdateCommunity(Box<UpdateCommunity>),
|
||||||
BlockUserFromCommunity(BlockUserFromCommunity),
|
BlockUserFromCommunity(BlockUserFromCommunity),
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
||||||
AddMod(AddMod),
|
AddMod(AddMod),
|
||||||
|
RemoveMod(RemoveMod),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
|
#[derive(Clone, Debug, Deserialize, Serialize, ActivityHandler)]
|
||||||
|
@ -65,14 +62,14 @@ pub enum SharedInboxActivities {
|
||||||
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
CreateOrUpdatePost(Box<CreateOrUpdatePost>),
|
||||||
Vote(Vote),
|
Vote(Vote),
|
||||||
UndoVote(UndoVote),
|
UndoVote(UndoVote),
|
||||||
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
|
Delete(Delete),
|
||||||
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
|
UndoDelete(UndoDelete),
|
||||||
RemovePostCommentOrCommunity(RemovePostCommentCommunityOrMod),
|
|
||||||
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
|
||||||
UpdateCommunity(Box<UpdateCommunity>),
|
UpdateCommunity(Box<UpdateCommunity>),
|
||||||
BlockUserFromCommunity(BlockUserFromCommunity),
|
BlockUserFromCommunity(BlockUserFromCommunity),
|
||||||
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
|
||||||
AddMod(AddMod),
|
AddMod(AddMod),
|
||||||
|
RemoveMod(RemoveMod),
|
||||||
// received by person
|
// received by person
|
||||||
AcceptFollowCommunity(AcceptFollowCommunity),
|
AcceptFollowCommunity(AcceptFollowCommunity),
|
||||||
// Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
|
// Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
|
||||||
|
|
|
@ -102,25 +102,6 @@ pub(crate) fn check_is_apub_id_valid(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
|
|
||||||
/// and actors in Lemmy.
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
pub trait ApubObjectType {
|
|
||||||
async fn send_delete(&self, creator: &DbPerson, context: &LemmyContext)
|
|
||||||
-> Result<(), LemmyError>;
|
|
||||||
async fn send_undo_delete(
|
|
||||||
&self,
|
|
||||||
creator: &DbPerson,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError>;
|
|
||||||
async fn send_remove(&self, mod_: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>;
|
|
||||||
async fn send_undo_remove(
|
|
||||||
&self,
|
|
||||||
mod_: &DbPerson,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<(), LemmyError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Common methods provided by ActivityPub actors (community and person). Not all methods are
|
/// Common methods provided by ActivityPub actors (community and person). Not all methods are
|
||||||
/// implemented by all actors.
|
/// implemented by all actors.
|
||||||
trait ActorType {
|
trait ActorType {
|
||||||
|
@ -160,11 +141,6 @@ pub trait CommunityType {
|
||||||
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
|
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
|
||||||
|
|
||||||
async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
|
async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
|
||||||
async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
|
|
||||||
async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError>;
|
|
||||||
|
|
||||||
async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>;
|
|
||||||
async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>;
|
|
||||||
|
|
||||||
async fn send_announce(
|
async fn send_announce(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -15,3 +15,15 @@ pub enum CommentInReplyToMigration {
|
||||||
Old(Vec<Url>),
|
Old(Vec<Url>),
|
||||||
New(Url),
|
New(Url),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Another migration we are doing is to handle all deletions and removals using Delete activity.
|
||||||
|
// This is because Remove is for removing an object from a collection, so using it that way doesn't
|
||||||
|
// really make sense. It is also a problem because we have a RemoveMod activity, which was awkward
|
||||||
|
// to handle together with removing posts etc.
|
||||||
|
//
|
||||||
|
// v0.11: send and receive mod removals as Remove
|
||||||
|
// v0.12: receive removals as Remove, send as Delete (compatible with v0.11)
|
||||||
|
// v0.13: send and receive mod removals as Delete (compatible with v0.12)
|
||||||
|
//
|
||||||
|
// For v0.13, delete [`UndoRemovePostCommentOrCommunity`], and don't handle object deletion in
|
||||||
|
// [`RemoveMod`] handler.
|
||||||
|
|
Loading…
Reference in a new issue