This commit is contained in:
parent
dd865c5af5
commit
788924d7ff
38 changed files with 452 additions and 568 deletions
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
|||
get_local_user_view_from_jwt,
|
||||
is_mod_or_admin,
|
||||
};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::Comment,
|
||||
|
@ -83,21 +83,7 @@ impl PerformCrud for DeleteComment {
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Send the apub message
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_comment.post.community_id)
|
||||
})
|
||||
.await??;
|
||||
send_apub_delete(
|
||||
&local_user_view.person.clone().into(),
|
||||
&community.clone().into(),
|
||||
DeletableObjects::Comment(Box::new(updated_comment.into())),
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_comment_ws_message(
|
||||
let res = send_comment_ws_message(
|
||||
data.comment_id,
|
||||
UserOperationCrud::DeleteComment,
|
||||
websocket_id,
|
||||
|
@ -106,7 +92,25 @@ impl PerformCrud for DeleteComment {
|
|||
recipient_ids,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// Send the apub message
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_comment.post.community_id)
|
||||
})
|
||||
.await??;
|
||||
let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
community,
|
||||
deletable,
|
||||
None,
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,22 +182,7 @@ impl PerformCrud for RemoveComment {
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Send the apub message
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_comment.post.community_id)
|
||||
})
|
||||
.await??;
|
||||
send_apub_remove(
|
||||
&local_user_view.person.clone().into(),
|
||||
&community.into(),
|
||||
DeletableObjects::Comment(Box::new(updated_comment.into())),
|
||||
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_comment_ws_message(
|
||||
let res = send_comment_ws_message(
|
||||
data.comment_id,
|
||||
UserOperationCrud::RemoveComment,
|
||||
websocket_id,
|
||||
|
@ -202,6 +191,24 @@ impl PerformCrud for RemoveComment {
|
|||
recipient_ids,
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// Send the apub message
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_comment.post.community_id)
|
||||
})
|
||||
.await??;
|
||||
let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
community,
|
||||
deletable,
|
||||
data.reason.clone().or_else(|| Some("".to_string())),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::PerformCrud;
|
||||
use actix_web::web::Data;
|
||||
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::Community,
|
||||
|
@ -49,24 +49,28 @@ impl PerformCrud for DeleteCommunity {
|
|||
.map_err(LemmyError::from)
|
||||
.map_err(|e| e.with_message("couldnt_update_community"))?;
|
||||
|
||||
// Send apub messages
|
||||
send_apub_delete(
|
||||
&local_user_view.person.clone().into(),
|
||||
&updated_community.clone().into(),
|
||||
DeletableObjects::Community(Box::new(updated_community.into())),
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_community_ws_message(
|
||||
let res = send_community_ws_message(
|
||||
data.community_id,
|
||||
UserOperationCrud::DeleteCommunity,
|
||||
websocket_id,
|
||||
Some(local_user_view.person.id),
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// Send apub messages
|
||||
let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
updated_community,
|
||||
deletable,
|
||||
None,
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,24 +115,26 @@ impl PerformCrud for RemoveCommunity {
|
|||
})
|
||||
.await??;
|
||||
|
||||
// Apub messages
|
||||
send_apub_remove(
|
||||
&local_user_view.person.clone().into(),
|
||||
&updated_community.clone().into(),
|
||||
DeletableObjects::Community(Box::new(updated_community.into())),
|
||||
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_community_ws_message(
|
||||
let res = send_community_ws_message(
|
||||
data.community_id,
|
||||
UserOperationCrud::RemoveCommunity,
|
||||
websocket_id,
|
||||
Some(local_user_view.person.id),
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// Apub messages
|
||||
let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
updated_community,
|
||||
deletable,
|
||||
data.reason.clone().or_else(|| Some("".to_string())),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use lemmy_api_common::{
|
|||
is_mod_or_admin,
|
||||
post::*,
|
||||
};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
|
||||
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::Community,
|
||||
|
@ -63,28 +63,31 @@ impl PerformCrud for DeletePost {
|
|||
})
|
||||
.await??;
|
||||
|
||||
// apub updates
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_post.community_id)
|
||||
})
|
||||
.await??;
|
||||
send_apub_delete(
|
||||
&local_user_view.person.clone().into(),
|
||||
&community.into(),
|
||||
DeletableObjects::Post(Box::new(updated_post.into())),
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_post_ws_message(
|
||||
let res = send_post_ws_message(
|
||||
data.post_id,
|
||||
UserOperationCrud::DeletePost,
|
||||
websocket_id,
|
||||
Some(local_user_view.person.id),
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// apub updates
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_post.community_id)
|
||||
})
|
||||
.await??;
|
||||
let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
community,
|
||||
deletable,
|
||||
None,
|
||||
deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,28 +143,30 @@ impl PerformCrud for RemovePost {
|
|||
})
|
||||
.await??;
|
||||
|
||||
// apub updates
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_post.community_id)
|
||||
})
|
||||
.await??;
|
||||
send_apub_remove(
|
||||
&local_user_view.person.clone().into(),
|
||||
&community.into(),
|
||||
DeletableObjects::Post(Box::new(updated_post.into())),
|
||||
data.reason.clone().unwrap_or_else(|| "".to_string()),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
send_post_ws_message(
|
||||
let res = send_post_ws_message(
|
||||
data.post_id,
|
||||
UserOperationCrud::RemovePost,
|
||||
websocket_id,
|
||||
Some(local_user_view.person.id),
|
||||
context,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
// apub updates
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, orig_post.community_id)
|
||||
})
|
||||
.await??;
|
||||
let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
|
||||
send_apub_delete_in_community(
|
||||
local_user_view.person,
|
||||
community,
|
||||
deletable,
|
||||
data.reason.clone().or_else(|| Some("".to_string())),
|
||||
removed,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_api_common::{
|
|||
use lemmy_apub::{
|
||||
generate_local_apub_endpoint,
|
||||
protocol::activities::{
|
||||
private_message::create_or_update::CreateOrUpdatePrivateMessage,
|
||||
create_or_update::private_message::CreateOrUpdatePrivateMessage,
|
||||
CreateOrUpdateType,
|
||||
},
|
||||
EndpointType,
|
||||
|
|
|
@ -5,14 +5,8 @@ use lemmy_api_common::{
|
|||
get_local_user_view_from_jwt,
|
||||
person::{DeletePrivateMessage, PrivateMessageResponse},
|
||||
};
|
||||
use lemmy_apub::protocol::activities::private_message::{
|
||||
delete::DeletePrivateMessage as DeletePrivateMessageApub,
|
||||
undo_delete::UndoDeletePrivateMessage,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::private_message::PrivateMessage,
|
||||
traits::{Crud, DeleteableOrRemoveable},
|
||||
};
|
||||
use lemmy_apub::activities::deletion::send_apub_delete_private_message;
|
||||
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
|
||||
use lemmy_utils::{ConnectionId, LemmyError};
|
||||
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
|
||||
|
||||
|
@ -51,23 +45,13 @@ impl PerformCrud for DeletePrivateMessage {
|
|||
.map_err(|e| e.with_message("couldnt_update_private_message"))?;
|
||||
|
||||
// Send the apub update
|
||||
if data.deleted {
|
||||
DeletePrivateMessageApub::send(
|
||||
&local_user_view.person.into(),
|
||||
&updated_private_message
|
||||
.blank_out_deleted_or_removed_info()
|
||||
.into(),
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
UndoDeletePrivateMessage::send(
|
||||
&local_user_view.person.into(),
|
||||
&updated_private_message.into(),
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
send_apub_delete_private_message(
|
||||
&local_user_view.person.into(),
|
||||
updated_private_message,
|
||||
data.deleted,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let op = UserOperationCrud::DeletePrivateMessage;
|
||||
send_pm_ws_message(data.private_message_id, op, websocket_id, context).await
|
||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_api_common::{
|
|||
person::{EditPrivateMessage, PrivateMessageResponse},
|
||||
};
|
||||
use lemmy_apub::protocol::activities::{
|
||||
private_message::create_or_update::CreateOrUpdatePrivateMessage,
|
||||
create_or_update::private_message::CreateOrUpdatePrivateMessage,
|
||||
CreateOrUpdateType,
|
||||
};
|
||||
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"object": {
|
||||
"id": "http://ds9.lemmy.ml/post/1",
|
||||
"type": "Tombstone"
|
||||
},
|
||||
"object": "http://ds9.lemmy.ml/post/1",
|
||||
"cc": [
|
||||
"http://enterprise.lemmy.ml/c/main"
|
||||
],
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"object": {
|
||||
"id": "http://ds9.lemmy.ml/comment/1",
|
||||
"type": "Tombstone"
|
||||
},
|
||||
"object": "http://ds9.lemmy.ml/comment/1",
|
||||
"cc": [
|
||||
"http://enterprise.lemmy.ml/c/main"
|
||||
],
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"object": {
|
||||
"id": "http://ds9.lemmy.ml/post/1",
|
||||
"type": "Tombstone"
|
||||
},
|
||||
"object": "http://ds9.lemmy.ml/post/1",
|
||||
"cc": [
|
||||
"http://enterprise.lemmy.ml/c/main"
|
||||
],
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"object": {
|
||||
"id": "http://ds9.lemmy.ml/comment/1",
|
||||
"type": "Tombstone"
|
||||
},
|
||||
"object": "http://ds9.lemmy.ml/comment/1",
|
||||
"cc": [
|
||||
"http://enterprise.lemmy.ml/c/main"
|
||||
],
|
||||
|
|
26
crates/apub/assets/mastodon/activities/delete.json
Normal file
26
crates/apub/assets/mastodon/activities/delete.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"ostatus": "http://ostatus.org#",
|
||||
"atomUri": "ostatus:atomUri"
|
||||
}
|
||||
],
|
||||
"id": "https://mastodon.madrid/users/felix/statuses/107773559874184870#delete",
|
||||
"type": "Delete",
|
||||
"actor": "https://mastodon.madrid/users/felix",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"object": {
|
||||
"id": "https://mastodon.madrid/users/felix/statuses/107773559874184870",
|
||||
"type": "Tombstone",
|
||||
"atomUri": "https://mastodon.madrid/users/felix/statuses/107773559874184870"
|
||||
},
|
||||
"signature": {
|
||||
"type": "RsaSignature2017",
|
||||
"creator": "https://mastodon.madrid/users/felix#main-key",
|
||||
"created": "2022-02-10T11:54:18Z",
|
||||
"signatureValue": "NjGnbkvouSP/cSusR7+sz39iEYxWXCu6nFmBXU3t8ETPkmbpMF5ASeJixXvpTOqbOfkMoWfXncw+jDsbqZ3ELaHGG1gZ5wHWym7mk7YCjQokpF3oPhTWmlEJCVKgewXMrfI4Ok8GGsUMGzuki9EyBDGc/UNBMEAhcxV5Huu7QSQDowcbIwxS3ImxFmtKFceh6mv/kMiXUerCgkYSm6rYZeXZGMTUpvcn9gP6X6Ed6UsrLjCSb3Fj0Naz7LHtzZXRSZDZF/SX2Vw/xKJIgEGzSCv+LKZGvEEkK8PPfMJJhi8cBJebkqOnBGtE6gYK2z2cm/oGorZtXU2L05pXmLAlYQ=="
|
||||
}
|
||||
}
|
35
crates/apub/assets/pleroma/activities/delete.json
Normal file
35
crates/apub/assets/pleroma/activities/delete.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://greenish.red/schemas/litepub-0.1.jsonld",
|
||||
{
|
||||
"@language": "und"
|
||||
}
|
||||
],
|
||||
"actor": "https://greenish.red/users/vpzom",
|
||||
"attachment": [],
|
||||
"attributedTo": "https://greenish.red/users/vpzom",
|
||||
"cc": [],
|
||||
"conversation": null,
|
||||
"id": "https://greenish.red/activities/52f0b259-596e-429f-8a1b-c0b455f8932b",
|
||||
"object": "https://greenish.red/objects/38e2b983-ebf5-4387-9bc2-3b80305469c9",
|
||||
"tag": [
|
||||
{
|
||||
"href": "https://voyager.lemmy.ml/c/main",
|
||||
"name": "@main@voyager.lemmy.ml",
|
||||
"type": "Mention"
|
||||
},
|
||||
{
|
||||
"href": "https://voyager.lemmy.ml/u/dess_voy_41u2",
|
||||
"name": "@dess_voy_41u2@voyager.lemmy.ml",
|
||||
"type": "Mention"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
"https://greenish.red/users/vpzom/followers",
|
||||
"https://voyager.lemmy.ml/c/main",
|
||||
"https://voyager.lemmy.ml/u/dess_voy_41u2",
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"type": "Delete"
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{
|
||||
activities::{
|
||||
check_community_deleted_or_removed,
|
||||
comment::get_notif_recipients,
|
||||
community::{announce::GetCommunity, send_activity_in_community},
|
||||
create_or_update::get_comment_notif_recipients,
|
||||
generate_activity_id,
|
||||
verify_activity,
|
||||
verify_is_public,
|
||||
|
@ -114,7 +114,7 @@ impl ActivityHandler for CreateOrUpdateComment {
|
|||
) -> Result<(), LemmyError> {
|
||||
let comment = ApubComment::from_apub(self.object, context, request_counter).await?;
|
||||
let do_send_email = self.kind == CreateOrUpdateType::Create;
|
||||
let recipients = get_notif_recipients(
|
||||
let recipients = get_comment_notif_recipients(
|
||||
&self.actor,
|
||||
&comment,
|
||||
do_send_email,
|
|
@ -9,10 +9,12 @@ use lemmy_db_schema::{
|
|||
use lemmy_utils::{utils::scrape_text_for_mentions, LemmyError};
|
||||
use lemmy_websocket::{send::send_local_notifs, LemmyContext};
|
||||
|
||||
pub mod create_or_update;
|
||||
pub mod comment;
|
||||
pub mod post;
|
||||
pub mod private_message;
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn get_notif_recipients(
|
||||
async fn get_comment_notif_recipients(
|
||||
actor: &ObjectId<ApubPerson>,
|
||||
comment: &Comment,
|
||||
do_send_email: bool,
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person},
|
||||
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
||||
protocol::activities::{
|
||||
private_message::create_or_update::CreateOrUpdatePrivateMessage,
|
||||
create_or_update::private_message::CreateOrUpdatePrivateMessage,
|
||||
CreateOrUpdateType,
|
||||
},
|
||||
};
|
|
@ -1,22 +1,17 @@
|
|||
use crate::{
|
||||
activities::{
|
||||
community::{announce::GetCommunity, send_activity_in_community},
|
||||
community::announce::GetCommunity,
|
||||
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
|
||||
generate_activity_id,
|
||||
verify_activity,
|
||||
verify_is_public,
|
||||
},
|
||||
activity_lists::AnnouncableActivities,
|
||||
objects::{community::ApubCommunity, person::ApubPerson},
|
||||
protocol::activities::deletion::delete::Delete,
|
||||
protocol::activities::deletion::delete::{Delete, IdOrNestedObject},
|
||||
};
|
||||
use activitystreams_kinds::{activity::DeleteType, public};
|
||||
use activitystreams_kinds::activity::DeleteType;
|
||||
use anyhow::anyhow;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub_lib::{
|
||||
data::Data,
|
||||
object_id::ObjectId,
|
||||
traits::{ActivityHandler, ActorType},
|
||||
};
|
||||
use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::Comment,
|
||||
|
@ -29,6 +24,7 @@ use lemmy_db_schema::{
|
|||
ModRemovePost,
|
||||
ModRemovePostForm,
|
||||
},
|
||||
person::Person,
|
||||
post::Post,
|
||||
},
|
||||
traits::Crud,
|
||||
|
@ -51,18 +47,8 @@ impl ActivityHandler for Delete {
|
|||
context: &Data<LemmyContext>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_is_public(&self.to, &[])?;
|
||||
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
|
||||
let community = self.get_community(context, request_counter).await?;
|
||||
verify_delete_activity(
|
||||
&self.object.id,
|
||||
&self.actor,
|
||||
&community,
|
||||
self.summary.is_some(),
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await?;
|
||||
verify_delete_activity(self, self.summary.is_some(), context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -82,53 +68,50 @@ impl ActivityHandler for Delete {
|
|||
};
|
||||
receive_remove_action(
|
||||
&self.actor,
|
||||
&self.object.id,
|
||||
self.object.id(),
|
||||
reason,
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
receive_delete_action(&self.object.id, &self.actor, true, context, request_counter).await
|
||||
receive_delete_action(
|
||||
self.object.id(),
|
||||
&self.actor,
|
||||
true,
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Delete {
|
||||
pub(in crate::activities::deletion) fn new(
|
||||
actor: &ApubPerson,
|
||||
actor: &Person,
|
||||
object: DeletableObjects,
|
||||
to: Url,
|
||||
community: Option<&Community>,
|
||||
summary: Option<String>,
|
||||
context: &LemmyContext,
|
||||
) -> Result<Delete, LemmyError> {
|
||||
let id = generate_activity_id(
|
||||
DeleteType::Delete,
|
||||
&context.settings().get_protocol_and_hostname(),
|
||||
)?;
|
||||
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
||||
Ok(Delete {
|
||||
actor: ObjectId::new(actor.actor_id()),
|
||||
to: vec![public()],
|
||||
object: object.to_tombstone()?,
|
||||
actor: ObjectId::new(actor.actor_id.clone()),
|
||||
to: vec![to],
|
||||
object: IdOrNestedObject::Id(object.id()),
|
||||
cc: cc.into_iter().collect(),
|
||||
kind: DeleteType::Delete,
|
||||
summary,
|
||||
id: generate_activity_id(
|
||||
DeleteType::Delete,
|
||||
&context.settings().get_protocol_and_hostname(),
|
||||
)?,
|
||||
id,
|
||||
unparsed: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(in crate::activities::deletion) async fn send(
|
||||
actor: &ApubPerson,
|
||||
community: &ApubCommunity,
|
||||
object: DeletableObjects,
|
||||
summary: Option<String>,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let delete = Delete::new(actor, object, summary, context)?;
|
||||
let delete_id = delete.id.clone();
|
||||
|
||||
let activity = AnnouncableActivities::Delete(delete);
|
||||
send_activity_in_community(activity, &delete_id, actor, community, vec![], context).await
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -204,6 +187,7 @@ pub(in crate::activities) async fn receive_remove_action(
|
|||
|
||||
send_comment_ws_message_simple(removed_comment.id, RemoveComment, context).await?;
|
||||
}
|
||||
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -216,13 +200,16 @@ impl GetCommunity for Delete {
|
|||
context: &LemmyContext,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<ApubCommunity, LemmyError> {
|
||||
let community_id = match DeletableObjects::read_from_db(&self.object.id, context).await? {
|
||||
let community_id = match DeletableObjects::read_from_db(self.object.id(), context).await? {
|
||||
DeletableObjects::Community(c) => c.id,
|
||||
DeletableObjects::Comment(c) => {
|
||||
let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??;
|
||||
post.community_id
|
||||
}
|
||||
DeletableObjects::Post(p) => p.community_id,
|
||||
DeletableObjects::PrivateMessage(_) => {
|
||||
return Err(anyhow!("Private message is not part of community").into())
|
||||
}
|
||||
};
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
Community::read(conn, community_id)
|
||||
|
|
|
@ -1,62 +1,117 @@
|
|||
use crate::{
|
||||
activities::{verify_mod_action, verify_person_in_community},
|
||||
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||
protocol::{
|
||||
activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
objects::tombstone::Tombstone,
|
||||
activities::{
|
||||
community::{announce::GetCommunity, send_activity_in_community},
|
||||
send_lemmy_activity,
|
||||
verify_is_public,
|
||||
verify_mod_action,
|
||||
verify_person,
|
||||
verify_person_in_community,
|
||||
},
|
||||
activity_lists::AnnouncableActivities,
|
||||
objects::{
|
||||
comment::ApubComment,
|
||||
community::ApubCommunity,
|
||||
person::ApubPerson,
|
||||
post::ApubPost,
|
||||
private_message::ApubPrivateMessage,
|
||||
},
|
||||
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
};
|
||||
use activitystreams_kinds::public;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject, verify::verify_domains_match};
|
||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
||||
use lemmy_apub_lib::{
|
||||
object_id::ObjectId,
|
||||
traits::{ActorType, ApubObject},
|
||||
verify::verify_domains_match,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
comment::Comment,
|
||||
community::Community,
|
||||
person::Person,
|
||||
post::Post,
|
||||
private_message::PrivateMessage,
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{
|
||||
send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
|
||||
send::{
|
||||
send_comment_ws_message_simple,
|
||||
send_community_ws_message,
|
||||
send_pm_ws_message,
|
||||
send_post_ws_message,
|
||||
},
|
||||
LemmyContext,
|
||||
UserOperationCrud,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use url::Url;
|
||||
|
||||
pub mod delete;
|
||||
pub mod undo_delete;
|
||||
|
||||
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
|
||||
/// action was done by a normal user.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn send_apub_delete(
|
||||
actor: &ApubPerson,
|
||||
community: &ApubCommunity,
|
||||
pub async fn send_apub_delete_in_community(
|
||||
actor: Person,
|
||||
community: Community,
|
||||
object: DeletableObjects,
|
||||
reason: Option<String>,
|
||||
deleted: bool,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
if deleted {
|
||||
Delete::send(actor, community, object, None, context).await
|
||||
let (id, activity) = if deleted {
|
||||
let delete = Delete::new(&actor, object, public(), Some(&community), reason, context)?;
|
||||
(delete.id.clone(), AnnouncableActivities::Delete(delete))
|
||||
} else {
|
||||
UndoDelete::send(actor, community, object, None, context).await
|
||||
}
|
||||
let undo = UndoDelete::new(&actor, object, public(), Some(&community), reason, context)?;
|
||||
(undo.id.clone(), AnnouncableActivities::UndoDelete(undo))
|
||||
};
|
||||
send_activity_in_community(
|
||||
activity,
|
||||
&id,
|
||||
&ApubPerson::from(actor),
|
||||
&community.into(),
|
||||
vec![],
|
||||
context,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its
|
||||
// ugly
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn send_apub_remove(
|
||||
pub async fn send_apub_delete_private_message(
|
||||
actor: &ApubPerson,
|
||||
community: &ApubCommunity,
|
||||
object: DeletableObjects,
|
||||
reason: String,
|
||||
removed: bool,
|
||||
pm: PrivateMessage,
|
||||
deleted: bool,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
if removed {
|
||||
Delete::send(actor, community, object, Some(reason), context).await
|
||||
let recipient_id = pm.recipient_id;
|
||||
let recipient: ApubPerson =
|
||||
blocking(context.pool(), move |conn| Person::read(conn, recipient_id))
|
||||
.await??
|
||||
.into();
|
||||
|
||||
let deletable = DeletableObjects::PrivateMessage(Box::new(pm.into()));
|
||||
let inbox = vec![recipient.shared_inbox_or_inbox_url()];
|
||||
if deleted {
|
||||
let delete = Delete::new(actor, deletable, recipient.actor_id(), None, None, context)?;
|
||||
let id = delete.id.clone();
|
||||
send_lemmy_activity(context, &delete, &id, actor, inbox, true).await?;
|
||||
} else {
|
||||
UndoDelete::send(actor, community, object, Some(reason), context).await
|
||||
}
|
||||
let undo = UndoDelete::new(actor, deletable, recipient.actor_id(), None, None, context)?;
|
||||
let id = undo.id.clone();
|
||||
send_lemmy_activity(context, &undo, &id, actor, inbox, true).await?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub enum DeletableObjects {
|
||||
Community(Box<ApubCommunity>),
|
||||
Comment(Box<ApubComment>),
|
||||
Post(Box<ApubPost>),
|
||||
PrivateMessage(Box<ApubPrivateMessage>),
|
||||
}
|
||||
|
||||
impl DeletableObjects {
|
||||
|
@ -74,43 +129,47 @@ impl DeletableObjects {
|
|||
if let Some(c) = ApubComment::read_from_apub_id(ap_id.clone(), context).await? {
|
||||
return Ok(DeletableObjects::Comment(Box::new(c)));
|
||||
}
|
||||
if let Some(p) = ApubPrivateMessage::read_from_apub_id(ap_id.clone(), context).await? {
|
||||
return Ok(DeletableObjects::PrivateMessage(Box::new(p)));
|
||||
}
|
||||
Err(diesel::NotFound.into())
|
||||
}
|
||||
|
||||
pub(crate) fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
|
||||
pub(crate) fn id(&self) -> Url {
|
||||
match self {
|
||||
DeletableObjects::Community(c) => c.to_tombstone(),
|
||||
DeletableObjects::Comment(c) => c.to_tombstone(),
|
||||
DeletableObjects::Post(p) => p.to_tombstone(),
|
||||
DeletableObjects::Community(c) => c.actor_id(),
|
||||
DeletableObjects::Comment(c) => c.ap_id.clone().into(),
|
||||
DeletableObjects::Post(p) => p.ap_id.clone().into(),
|
||||
DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(in crate::activities) async fn verify_delete_activity(
|
||||
object: &Url,
|
||||
actor: &ObjectId<ApubPerson>,
|
||||
community: &ApubCommunity,
|
||||
activity: &Delete,
|
||||
is_mod_action: bool,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let object = DeletableObjects::read_from_db(object, context).await?;
|
||||
let object = DeletableObjects::read_from_db(activity.object.id(), context).await?;
|
||||
match object {
|
||||
DeletableObjects::Community(community) => {
|
||||
verify_is_public(&activity.to, &[])?;
|
||||
if community.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(actor, &community, context, request_counter).await?;
|
||||
verify_person_in_community(&activity.actor, &community, context, request_counter).await?;
|
||||
}
|
||||
// community deletion is always a mod (or admin) action
|
||||
verify_mod_action(actor, &community, context, request_counter).await?;
|
||||
verify_mod_action(&activity.actor, &community, context, request_counter).await?;
|
||||
}
|
||||
DeletableObjects::Post(p) => {
|
||||
verify_delete_activity_post_or_comment(
|
||||
actor,
|
||||
verify_is_public(&activity.to, &[])?;
|
||||
verify_delete_post_or_comment(
|
||||
&activity.actor,
|
||||
&p.ap_id.clone().into(),
|
||||
community,
|
||||
&activity.get_community(context, request_counter).await?,
|
||||
is_mod_action,
|
||||
context,
|
||||
request_counter,
|
||||
|
@ -118,22 +177,27 @@ pub(in crate::activities) async fn verify_delete_activity(
|
|||
.await?;
|
||||
}
|
||||
DeletableObjects::Comment(c) => {
|
||||
verify_delete_activity_post_or_comment(
|
||||
actor,
|
||||
verify_is_public(&activity.to, &[])?;
|
||||
verify_delete_post_or_comment(
|
||||
&activity.actor,
|
||||
&c.ap_id.clone().into(),
|
||||
community,
|
||||
&activity.get_community(context, request_counter).await?,
|
||||
is_mod_action,
|
||||
context,
|
||||
request_counter,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
DeletableObjects::PrivateMessage(_) => {
|
||||
verify_person(&activity.actor, context, request_counter).await?;
|
||||
verify_domains_match(activity.actor.inner(), activity.object.id())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn verify_delete_activity_post_or_comment(
|
||||
async fn verify_delete_post_or_comment(
|
||||
actor: &ObjectId<ApubPerson>,
|
||||
object_id: &Url,
|
||||
community: &ApubCommunity,
|
||||
|
@ -152,8 +216,6 @@ async fn verify_delete_activity_post_or_comment(
|
|||
}
|
||||
|
||||
/// Write deletion or restoring of an object to the database, and send websocket message.
|
||||
/// TODO: we should do something similar for receive_remove_action(), but its much more complicated
|
||||
/// because of the mod log
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn receive_delete_action(
|
||||
object: &Url,
|
||||
|
@ -165,11 +227,14 @@ async fn receive_delete_action(
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
let mod_ = actor
|
||||
let mod_: Person = actor
|
||||
.dereference(context, context.client(), request_counter)
|
||||
.await?;
|
||||
.await?
|
||||
.deref()
|
||||
.clone();
|
||||
let object = DeletableObjects::Community(community.clone());
|
||||
send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
|
||||
let c: Community = community.deref().deref().clone();
|
||||
send_apub_delete_in_community(mod_, c, object, None, true, context).await?;
|
||||
}
|
||||
|
||||
let community = blocking(context.pool(), move |conn| {
|
||||
|
@ -215,6 +280,20 @@ async fn receive_delete_action(
|
|||
.await?;
|
||||
}
|
||||
}
|
||||
DeletableObjects::PrivateMessage(pm) => {
|
||||
let deleted_private_message = blocking(context.pool(), move |conn| {
|
||||
PrivateMessage::update_deleted(conn, pm.id, deleted)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_pm_ws_message(
|
||||
deleted_private_message.id,
|
||||
UserOperationCrud::DeletePrivateMessage,
|
||||
None,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
use crate::{
|
||||
activities::{
|
||||
community::{announce::GetCommunity, send_activity_in_community},
|
||||
community::announce::GetCommunity,
|
||||
deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
|
||||
generate_activity_id,
|
||||
verify_activity,
|
||||
verify_is_public,
|
||||
},
|
||||
activity_lists::AnnouncableActivities,
|
||||
objects::{community::ApubCommunity, person::ApubPerson},
|
||||
objects::community::ApubCommunity,
|
||||
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
};
|
||||
use activitystreams_kinds::{activity::UndoType, public};
|
||||
use activitystreams_kinds::activity::UndoType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub_lib::{
|
||||
data::Data,
|
||||
object_id::ObjectId,
|
||||
traits::{ActivityHandler, ActorType},
|
||||
};
|
||||
use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
|
||||
use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler};
|
||||
use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{
|
||||
send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
|
||||
|
@ -36,14 +30,10 @@ impl ActivityHandler for UndoDelete {
|
|||
context: &Data<LemmyContext>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_is_public(&self.to, &self.cc)?;
|
||||
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
let community = self.get_community(context, request_counter).await?;
|
||||
verify_delete_activity(
|
||||
&self.object.object.id,
|
||||
&self.actor,
|
||||
&community,
|
||||
&self.object,
|
||||
self.object.summary.is_some(),
|
||||
context,
|
||||
request_counter,
|
||||
|
@ -59,10 +49,10 @@ impl ActivityHandler for UndoDelete {
|
|||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
if self.object.summary.is_some() {
|
||||
UndoDelete::receive_undo_remove_action(&self.object.object.id, context).await
|
||||
UndoDelete::receive_undo_remove_action(self.object.object.id(), context).await
|
||||
} else {
|
||||
receive_delete_action(
|
||||
&self.object.object.id,
|
||||
self.object.object.id(),
|
||||
&self.actor,
|
||||
false,
|
||||
context,
|
||||
|
@ -75,31 +65,30 @@ impl ActivityHandler for UndoDelete {
|
|||
|
||||
impl UndoDelete {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(in crate::activities::deletion) async fn send(
|
||||
actor: &ApubPerson,
|
||||
community: &ApubCommunity,
|
||||
pub(in crate::activities::deletion) fn new(
|
||||
actor: &Person,
|
||||
object: DeletableObjects,
|
||||
to: Url,
|
||||
community: Option<&Community>,
|
||||
summary: Option<String>,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let object = Delete::new(actor, object, summary, context)?;
|
||||
) -> Result<UndoDelete, LemmyError> {
|
||||
let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
|
||||
|
||||
let id = generate_activity_id(
|
||||
UndoType::Undo,
|
||||
&context.settings().get_protocol_and_hostname(),
|
||||
)?;
|
||||
let undo = UndoDelete {
|
||||
actor: ObjectId::new(actor.actor_id()),
|
||||
to: vec![public()],
|
||||
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
||||
Ok(UndoDelete {
|
||||
actor: ObjectId::new(actor.actor_id.clone()),
|
||||
to: vec![to],
|
||||
object,
|
||||
cc: vec![community.actor_id()],
|
||||
cc: cc.into_iter().collect(),
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
id,
|
||||
unparsed: Default::default(),
|
||||
};
|
||||
|
||||
let activity = AnnouncableActivities::UndoDelete(undo);
|
||||
send_activity_in_community(activity, &id, actor, community, vec![], context).await
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -135,6 +124,7 @@ impl UndoDelete {
|
|||
.await??;
|
||||
send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
|
||||
}
|
||||
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -26,12 +26,10 @@ use url::{ParseError, Url};
|
|||
use uuid::Uuid;
|
||||
|
||||
pub mod block;
|
||||
pub mod comment;
|
||||
pub mod community;
|
||||
pub mod create_or_update;
|
||||
pub mod deletion;
|
||||
pub mod following;
|
||||
pub mod post;
|
||||
pub mod private_message;
|
||||
pub mod voting;
|
||||
|
||||
/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
pub mod create_or_update;
|
|
@ -1,97 +0,0 @@
|
|||
use crate::{
|
||||
activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person},
|
||||
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
||||
protocol::activities::private_message::delete::DeletePrivateMessage,
|
||||
};
|
||||
use activitystreams_kinds::activity::DeleteType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub_lib::{
|
||||
data::Data,
|
||||
object_id::ObjectId,
|
||||
traits::{ActivityHandler, ActorType},
|
||||
verify::verify_domains_match,
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{person::Person, private_message::PrivateMessage},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
|
||||
|
||||
impl DeletePrivateMessage {
|
||||
pub(in crate::activities::private_message) fn new(
|
||||
actor: &ApubPerson,
|
||||
pm: &PrivateMessage,
|
||||
context: &LemmyContext,
|
||||
) -> Result<DeletePrivateMessage, LemmyError> {
|
||||
Ok(DeletePrivateMessage {
|
||||
actor: ObjectId::new(actor.actor_id()),
|
||||
to: [ObjectId::new(actor.actor_id())],
|
||||
object: ObjectId::new(pm.ap_id.clone()),
|
||||
kind: DeleteType::Delete,
|
||||
id: generate_activity_id(
|
||||
DeleteType::Delete,
|
||||
&context.settings().get_protocol_and_hostname(),
|
||||
)?,
|
||||
unparsed: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn send(
|
||||
actor: &ApubPerson,
|
||||
pm: &ApubPrivateMessage,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let delete = DeletePrivateMessage::new(actor, pm, context)?;
|
||||
let delete_id = delete.id.clone();
|
||||
|
||||
let recipient_id = pm.recipient_id;
|
||||
let recipient: ApubPerson =
|
||||
blocking(context.pool(), move |conn| Person::read(conn, recipient_id))
|
||||
.await??
|
||||
.into();
|
||||
let inbox = vec![recipient.shared_inbox_or_inbox_url()];
|
||||
send_lemmy_activity(context, &delete, &delete_id, actor, inbox, true).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ActivityHandler for DeletePrivateMessage {
|
||||
type DataType = LemmyContext;
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn verify(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
verify_domains_match(self.actor.inner(), self.object.inner())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn receive(
|
||||
self,
|
||||
context: &Data<LemmyContext>,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let private_message = self.object.dereference_local(context).await?;
|
||||
let deleted_private_message = blocking(context.pool(), move |conn| {
|
||||
PrivateMessage::update_deleted(conn, private_message.id, true)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_pm_ws_message(
|
||||
deleted_private_message.id,
|
||||
UserOperationCrud::DeletePrivateMessage,
|
||||
None,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
pub mod create_or_update;
|
||||
pub mod delete;
|
||||
pub mod undo_delete;
|
|
@ -1,97 +0,0 @@
|
|||
use crate::{
|
||||
activities::{generate_activity_id, send_lemmy_activity, verify_activity, verify_person},
|
||||
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
||||
protocol::activities::private_message::{
|
||||
delete::DeletePrivateMessage,
|
||||
undo_delete::UndoDeletePrivateMessage,
|
||||
},
|
||||
};
|
||||
use activitystreams_kinds::activity::UndoType;
|
||||
use lemmy_api_common::blocking;
|
||||
use lemmy_apub_lib::{
|
||||
data::Data,
|
||||
object_id::ObjectId,
|
||||
traits::{ActivityHandler, ActorType},
|
||||
verify::{verify_domains_match, verify_urls_match},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{person::Person, private_message::PrivateMessage},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::LemmyError;
|
||||
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
|
||||
|
||||
impl UndoDeletePrivateMessage {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn send(
|
||||
actor: &ApubPerson,
|
||||
pm: &ApubPrivateMessage,
|
||||
context: &LemmyContext,
|
||||
) -> Result<(), LemmyError> {
|
||||
let recipient_id = pm.recipient_id;
|
||||
let recipient: ApubPerson =
|
||||
blocking(context.pool(), move |conn| Person::read(conn, recipient_id))
|
||||
.await??
|
||||
.into();
|
||||
|
||||
let object = DeletePrivateMessage::new(actor, pm, context)?;
|
||||
let id = generate_activity_id(
|
||||
UndoType::Undo,
|
||||
&context.settings().get_protocol_and_hostname(),
|
||||
)?;
|
||||
let undo = UndoDeletePrivateMessage {
|
||||
actor: ObjectId::new(actor.actor_id()),
|
||||
to: [ObjectId::new(recipient.actor_id())],
|
||||
object,
|
||||
kind: UndoType::Undo,
|
||||
id: id.clone(),
|
||||
unparsed: Default::default(),
|
||||
};
|
||||
let inbox = vec![recipient.shared_inbox_or_inbox_url()];
|
||||
send_lemmy_activity(context, &undo, &id, actor, inbox, true).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl ActivityHandler for UndoDeletePrivateMessage {
|
||||
type DataType = LemmyContext;
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn verify(
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
verify_activity(&self.id, self.actor.inner(), &context.settings())?;
|
||||
verify_person(&self.actor, context, request_counter).await?;
|
||||
verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
|
||||
verify_domains_match(self.actor.inner(), self.object.object.inner())?;
|
||||
self.object.verify(context, request_counter).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn receive(
|
||||
self,
|
||||
context: &Data<LemmyContext>,
|
||||
_request_counter: &mut i32,
|
||||
) -> Result<(), LemmyError> {
|
||||
let ap_id = self.object.object.clone();
|
||||
let private_message = ap_id.dereference_local(context).await?;
|
||||
|
||||
let deleted_private_message = blocking(context.pool(), move |conn| {
|
||||
PrivateMessage::update_deleted(conn, private_message.id, false)
|
||||
})
|
||||
.await??;
|
||||
|
||||
send_pm_ws_message(
|
||||
deleted_private_message.id,
|
||||
UserOperationCrud::EditPrivateMessage,
|
||||
None,
|
||||
context,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -11,18 +11,17 @@ use crate::{
|
|||
report::Report,
|
||||
update::UpdateCommunity,
|
||||
},
|
||||
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
||||
create_or_update::{
|
||||
comment::CreateOrUpdateComment,
|
||||
post::CreateOrUpdatePost,
|
||||
private_message::CreateOrUpdatePrivateMessage,
|
||||
},
|
||||
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
following::{
|
||||
accept::AcceptFollowCommunity,
|
||||
follow::FollowCommunity,
|
||||
undo_follow::UndoFollowCommunity,
|
||||
},
|
||||
private_message::{
|
||||
create_or_update::CreateOrUpdatePrivateMessage,
|
||||
delete::DeletePrivateMessage,
|
||||
undo_delete::UndoDeletePrivateMessage,
|
||||
},
|
||||
voting::{undo_vote::UndoVote, vote::Vote},
|
||||
},
|
||||
objects::page::Page,
|
||||
|
@ -61,8 +60,8 @@ pub enum PersonInboxActivities {
|
|||
/// Some activities can also be sent from user to user, eg a comment with mentions
|
||||
AnnouncableActivities(AnnouncableActivities),
|
||||
CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
|
||||
DeletePrivateMessage(DeletePrivateMessage),
|
||||
UndoDeletePrivateMessage(UndoDeletePrivateMessage),
|
||||
Delete(Delete),
|
||||
UndoDelete(UndoDelete),
|
||||
AnnounceActivity(AnnounceActivity),
|
||||
}
|
||||
|
||||
|
|
|
@ -84,10 +84,14 @@ pub(in crate::http) async fn receive_group_inbox(
|
|||
let res = receive_activity(request, activity.clone(), activity_data, context).await?;
|
||||
|
||||
if let GroupInboxActivities::AnnouncableActivities(announcable) = activity {
|
||||
let community = announcable.get_community(context, &mut 0).await?;
|
||||
verify_person_in_community(&actor_id, &community, context, &mut 0).await?;
|
||||
if community.local {
|
||||
AnnounceActivity::send(*announcable, &community, context).await?;
|
||||
// Ignore failures in get_community(). those happen because Delete/PrivateMessage is not in a
|
||||
// community, but looks identical to Delete/Post or Delete/Comment which are in a community.
|
||||
let community = announcable.get_community(context, &mut 0).await;
|
||||
if let Ok(community) = community {
|
||||
if community.local {
|
||||
verify_person_in_community(&actor_id, &community, context, &mut 0).await?;
|
||||
AnnounceActivity::send(*announcable, &community, context).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod comment;
|
||||
pub mod post;
|
||||
pub mod private_message;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -7,7 +8,11 @@ mod tests {
|
|||
context::WithContext,
|
||||
objects::tests::file_to_json_object,
|
||||
protocol::{
|
||||
activities::create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
|
||||
activities::create_or_update::{
|
||||
comment::CreateOrUpdateComment,
|
||||
post::CreateOrUpdatePost,
|
||||
private_message::CreateOrUpdatePrivateMessage,
|
||||
},
|
||||
tests::test_parse_lemmy_item,
|
||||
},
|
||||
};
|
||||
|
@ -26,6 +31,10 @@ mod tests {
|
|||
"assets/lemmy/activities/create_or_update/create_note.json",
|
||||
)
|
||||
.unwrap();
|
||||
test_parse_lemmy_item::<CreateOrUpdatePrivateMessage>(
|
||||
"assets/lemmy/activities/create_or_update/create_private_message.json",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
file_to_json_object::<WithContext<CreateOrUpdateComment>>(
|
||||
"assets/pleroma/activities/create_note.json",
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
objects::person::ApubPerson,
|
||||
protocol::{objects::tombstone::Tombstone, Unparsed},
|
||||
};
|
||||
use crate::{objects::person::ApubPerson, protocol::Unparsed};
|
||||
use activitystreams_kinds::activity::DeleteType;
|
||||
use lemmy_apub_lib::object_id::ObjectId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -15,7 +12,11 @@ pub struct Delete {
|
|||
pub(crate) actor: ObjectId<ApubPerson>,
|
||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||
pub(crate) to: Vec<Url>,
|
||||
pub(crate) object: Tombstone,
|
||||
pub(crate) object: IdOrNestedObject,
|
||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub(crate) cc: Vec<Url>,
|
||||
#[serde(rename = "type")]
|
||||
pub(crate) kind: DeleteType,
|
||||
/// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
|
||||
|
@ -25,3 +26,26 @@ pub struct Delete {
|
|||
#[serde(flatten)]
|
||||
pub(crate) unparsed: Unparsed,
|
||||
}
|
||||
|
||||
/// Instead of a simple ID string as object, Mastodon sends a nested tombstone for some reason,
|
||||
/// so we need to handle that as well.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub(crate) enum IdOrNestedObject {
|
||||
Id(Url),
|
||||
NestedObject(NestedObject),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub(crate) struct NestedObject {
|
||||
id: Url,
|
||||
}
|
||||
|
||||
impl IdOrNestedObject {
|
||||
pub(crate) fn id(&self) -> &Url {
|
||||
match self {
|
||||
IdOrNestedObject::Id(i) => i,
|
||||
IdOrNestedObject::NestedObject(n) => &n.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,17 @@ pub mod undo_delete;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::protocol::{
|
||||
activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
tests::test_parse_lemmy_item,
|
||||
use crate::{
|
||||
context::WithContext,
|
||||
objects::tests::file_to_json_object,
|
||||
protocol::{
|
||||
activities::deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||
tests::test_parse_lemmy_item,
|
||||
},
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_parse_lemmy_deletion() {
|
||||
async fn test_parse_deletion() {
|
||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/remove_note.json").unwrap();
|
||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_page.json").unwrap();
|
||||
|
||||
|
@ -17,5 +21,14 @@ mod tests {
|
|||
.unwrap();
|
||||
test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_delete_page.json")
|
||||
.unwrap();
|
||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_private_message.json")
|
||||
.unwrap();
|
||||
test_parse_lemmy_item::<UndoDelete>(
|
||||
"assets/lemmy/activities/deletion/undo_delete_private_message.json",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
file_to_json_object::<WithContext<Delete>>("assets/pleroma/activities/delete.json").unwrap();
|
||||
file_to_json_object::<WithContext<Delete>>("assets/mastodon/activities/delete.json").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ pub struct UndoDelete {
|
|||
pub(crate) to: Vec<Url>,
|
||||
pub(crate) object: Delete,
|
||||
#[serde(deserialize_with = "crate::deserialize_one_or_many")]
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub(crate) cc: Vec<Url>,
|
||||
#[serde(rename = "type")]
|
||||
pub(crate) kind: UndoType,
|
||||
|
|
|
@ -6,7 +6,6 @@ pub mod community;
|
|||
pub mod create_or_update;
|
||||
pub mod deletion;
|
||||
pub mod following;
|
||||
pub mod private_message;
|
||||
pub mod voting;
|
||||
|
||||
#[derive(Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
use crate::{
|
||||
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
|
||||
protocol::Unparsed,
|
||||
};
|
||||
use activitystreams_kinds::activity::DeleteType;
|
||||
use lemmy_apub_lib::object_id::ObjectId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeletePrivateMessage {
|
||||
pub(crate) actor: ObjectId<ApubPerson>,
|
||||
#[serde(deserialize_with = "crate::deserialize_one")]
|
||||
pub(crate) to: [ObjectId<ApubPerson>; 1],
|
||||
pub(crate) object: ObjectId<ApubPrivateMessage>,
|
||||
#[serde(rename = "type")]
|
||||
pub(crate) kind: DeleteType,
|
||||
pub(crate) id: Url,
|
||||
#[serde(flatten)]
|
||||
pub(crate) unparsed: Unparsed,
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
pub mod create_or_update;
|
||||
pub mod delete;
|
||||
pub mod undo_delete;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::protocol::{
|
||||
activities::private_message::{
|
||||
create_or_update::CreateOrUpdatePrivateMessage,
|
||||
delete::DeletePrivateMessage,
|
||||
undo_delete::UndoDeletePrivateMessage,
|
||||
},
|
||||
tests::test_parse_lemmy_item,
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_parse_lemmy_private_message() {
|
||||
test_parse_lemmy_item::<CreateOrUpdatePrivateMessage>(
|
||||
"assets/lemmy/activities/private_message/create.json",
|
||||
)
|
||||
.unwrap();
|
||||
test_parse_lemmy_item::<DeletePrivateMessage>(
|
||||
"assets/lemmy/activities/private_message/delete.json",
|
||||
)
|
||||
.unwrap();
|
||||
test_parse_lemmy_item::<UndoDeletePrivateMessage>(
|
||||
"assets/lemmy/activities/private_message/undo_delete.json",
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
use crate::{
|
||||
objects::person::ApubPerson,
|
||||
protocol::{activities::private_message::delete::DeletePrivateMessage, Unparsed},
|
||||
};
|
||||
use activitystreams_kinds::activity::UndoType;
|
||||
use lemmy_apub_lib::object_id::ObjectId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UndoDeletePrivateMessage {
|
||||
pub(crate) actor: ObjectId<ApubPerson>,
|
||||
#[serde(deserialize_with = "crate::deserialize_one")]
|
||||
pub(crate) to: [ObjectId<ApubPerson>; 1],
|
||||
pub(crate) object: DeletePrivateMessage,
|
||||
#[serde(rename = "type")]
|
||||
pub(crate) kind: UndoType,
|
||||
pub(crate) id: Url,
|
||||
#[serde(flatten)]
|
||||
pub(crate) unparsed: Unparsed,
|
||||
}
|
Loading…
Reference in a new issue