rework delete/remove activity receivers (still quite messy)

This commit is contained in:
Felix Ableitner 2021-07-13 05:17:32 +02:00
parent 28e960bd9c
commit 186c0b93d1
24 changed files with 573 additions and 727 deletions

View file

@ -2,19 +2,23 @@ use crate::{
activities::{
comment::{create::CreateComment, update::UpdateComment},
community::{block_user::BlockUserFromCommunity, undo_block_user::UndoBlockUserFromCommunity},
deletion::{
delete::DeletePostCommentOrCommunity,
undo_delete::UndoDeletePostCommentOrCommunity,
},
post::{create::CreatePost, update::UpdatePost},
post_or_comment::{
delete::DeletePostOrComment,
dislike::DislikePostOrComment,
like::LikePostOrComment,
remove::RemovePostOrComment,
undo_delete::UndoDeletePostOrComment,
undo_dislike::UndoDislikePostOrComment,
undo_like::UndoLikePostOrComment,
undo_remove::UndoRemovePostOrComment,
removal::{
remove::RemovePostCommentOrCommunity,
undo_remove::UndoRemovePostCommentOrCommunity,
},
verify_activity,
verify_community,
voting::{
dislike::DislikePostOrComment,
like::LikePostOrComment,
undo_dislike::UndoDislikePostOrComment,
undo_like::UndoLikePostOrComment,
},
},
http::is_activity_already_known,
};
@ -37,10 +41,10 @@ pub enum AnnouncableActivities {
DislikePostOrComment(DislikePostOrComment),
UndoLikePostOrComment(UndoLikePostOrComment),
UndoDislikePostOrComment(UndoDislikePostOrComment),
DeletePostOrComment(DeletePostOrComment),
RemovePostOrComment(RemovePostOrComment),
UndoRemovePostOrComment(UndoRemovePostOrComment),
UndoDeletePostOrComment(UndoDeletePostOrComment),
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
RemovePostCommentOrCommunity(RemovePostCommentOrCommunity),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
}

View file

@ -1,96 +0,0 @@
use crate::activities::{community::send_websocket_message, verify_mod_action};
use activitystreams::activity::kind::DeleteType;
use lemmy_api_common::blocking;
use lemmy_apub::{
check_is_apub_id_valid,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
ActorType,
CommunityType,
};
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::{source::community::Community_, ApubObject};
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
// We have two possibilities which need to be handled:
// 1. actor is remote mod, community id in object
// 2. actor is community, cc is followers collection
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteCommunity {
to: PublicUrl,
pub(in crate::activities::community) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: DeleteType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for DeleteCommunity {
async fn verify(&self, context: &LemmyContext, _: &mut i32) -> Result<(), LemmyError> {
verify_domains_match(&self.common.actor, self.common.id_unchecked())?;
let object = self.object.clone();
let community = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &object.into())
})
.await?;
// remote mod action on local community
if let Ok(c) = community {
verify_domains_match(&self.object, &self.cc[0])?;
check_is_apub_id_valid(&self.common.actor, false)?;
verify_mod_action(&self.common.actor, c.actor_id(), context).await
}
// community action sent to followers
else {
verify_domains_match(&self.common.actor, &self.object)?;
verify_domains_match(&self.common.actor, &self.cc[0])
}
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
// TODO: match on actor to decide what to do
let actor = self.object.clone();
let community = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &actor.into())
})
.await?;
let community_id = match community {
Ok(c) => {
// remote mod sent delete to local community, forward it to followers
let actor =
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
c.send_delete(actor, context).await?;
c.id
}
Err(_) => {
// refetch the remote community
let community =
get_or_fetch_and_upsert_community(&self.object, context, request_counter).await?;
community.id
}
};
let deleted_community = blocking(context.pool(), move |conn| {
Community::update_deleted(conn, community_id, true)
})
.await??;
send_websocket_message(
deleted_community.id,
UserOperationCrud::DeleteCommunity,
context,
)
.await
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -10,15 +10,13 @@ use url::Url;
pub mod add_mod;
pub mod announce;
pub mod block_user;
pub mod delete;
pub mod remove;
pub mod remove_mod;
pub mod undo_block_user;
pub mod undo_delete;
pub mod undo_remove;
pub mod update;
async fn send_websocket_message<OP: ToString + Send + lemmy_websocket::OperationType + 'static>(
pub(crate) async fn send_websocket_message<
OP: ToString + Send + lemmy_websocket::OperationType + 'static,
>(
community_id: CommunityId,
op: OP,
context: &LemmyContext,

View file

@ -1,60 +0,0 @@
use crate::activities::community::send_websocket_message;
use activitystreams::activity::kind::RemoveType;
use lemmy_api_common::blocking;
use lemmy_apub::check_is_apub_id_valid;
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::{source::community::Community_, ApubObject};
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoveCommunity {
to: PublicUrl,
pub(in crate::activities::community) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for RemoveCommunity {
async fn verify(&self, _context: &LemmyContext, _: &mut i32) -> Result<(), LemmyError> {
verify_domains_match(&self.common.actor, self.common.id_unchecked())?;
check_is_apub_id_valid(&self.common.actor, false)?;
verify_domains_match(&self.common.actor, &self.object)?;
verify_domains_match(&self.common.actor, &self.cc[0])
}
async fn receive(
&self,
context: &LemmyContext,
_request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object = self.object.clone();
// only search in local database, there is no reason to fetch something thats deleted
let community = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &object.into())
})
.await??;
let removed_community = blocking(context.pool(), move |conn| {
Community::update_removed(conn, community.id, true)
})
.await??;
send_websocket_message(
removed_community.id,
UserOperationCrud::RemoveCommunity,
context,
)
.await
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -1,103 +0,0 @@
use crate::activities::{
community::{delete::DeleteCommunity, send_websocket_message},
verify_mod_action,
};
use activitystreams::activity::kind::DeleteType;
use lemmy_api_common::blocking;
use lemmy_apub::{
check_is_apub_id_valid,
fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
ActorType,
CommunityType,
};
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::{source::community::Community_, ApubObject};
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
// We have two possibilities which need to be handled:
// 1. actor is remote mod, community id in object
// 2. actor is community, cc is followers collection
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoDeleteCommunity {
to: PublicUrl,
object: DeleteCommunity,
cc: [Url; 1],
#[serde(rename = "type")]
kind: DeleteType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDeleteCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_domains_match(&self.common.actor, self.common.id_unchecked())?;
let object = self.object.object.clone();
let community = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &object.into())
})
.await?;
// remote mod action on local community
if let Ok(c) = community {
verify_domains_match(&self.object.object, &self.cc[0])?;
check_is_apub_id_valid(&self.common.actor, false)?;
verify_mod_action(&self.common.actor, c.actor_id(), context).await?;
}
// community action sent to followers
else {
verify_domains_match(&self.common.actor, &self.object.object)?;
verify_domains_match(&self.common.actor, &self.cc[0])?;
}
self.object.verify(context, request_counter).await
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object = self.object.object.clone();
let community = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &object.into())
})
.await?;
let community_id = match community {
Ok(c) => {
// remote mod sent undo to local community, forward it to followers
let actor =
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
c.send_delete(actor, context).await?;
c.id
}
Err(_) => {
// refetch the remote community
let community =
get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await?;
community.id
}
};
let restored_community = blocking(context.pool(), move |conn| {
Community::update_deleted(conn, community_id, false)
})
.await??;
send_websocket_message(
restored_community.id,
UserOperationCrud::EditCommunity,
context,
)
.await
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -1,63 +0,0 @@
use crate::activities::community::{remove::RemoveCommunity, send_websocket_message};
use activitystreams::activity::kind::RemoveType;
use lemmy_api_common::blocking;
use lemmy_apub::{check_is_apub_id_valid, fetcher::community::get_or_fetch_and_upsert_community};
use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::source::community::Community_;
use lemmy_db_schema::source::community::Community;
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoRemoveCommunity {
to: PublicUrl,
object: RemoveCommunity,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoRemoveCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_domains_match(&self.common.actor, self.common.id_unchecked())?;
check_is_apub_id_valid(&self.common.actor, false)?;
verify_domains_match(&self.common.actor, &self.object.object)?;
verify_domains_match(&self.common.actor, &self.cc[0])?;
self.object.verify(context, request_counter).await
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let community_id = self.object.object.clone();
let community =
get_or_fetch_and_upsert_community(&community_id, context, request_counter).await?;
let restored_community = blocking(context.pool(), move |conn| {
Community::update_removed(conn, community.id, false)
})
.await??;
send_websocket_message(
restored_community.id,
UserOperationCrud::EditCommunity,
context,
)
.await
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -0,0 +1,158 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
community::send_websocket_message as send_community_message,
post::send_websocket_message as send_post_message,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::DeleteType;
use lemmy_api_common::blocking;
use lemmy_apub::{
fetcher::{
community::get_or_fetch_and_upsert_community,
objects::get_or_fetch_and_insert_post_or_comment,
person::get_or_fetch_and_upsert_person,
},
ActorType,
CommunityType,
PostOrComment,
};
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::{
source::{comment::Comment_, community::Community_, post::Post_},
Crud,
};
use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
/// This is very confusing, because there are four distinct cases to handle:
/// - user deletes their post
/// - user deletes their comment
/// - remote community mod deletes local community
/// - remote community deletes itself (triggered by a mod)
///
/// TODO: we should probably change how community deletions work to simplify this. Probably by
/// wrapping it in an announce just like other activities, instead of having the community send it.
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DeletePostCommentOrCommunity {
to: PublicUrl,
pub(in crate::activities::deletion) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: DeleteType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for DeletePostCommentOrCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
let object_community =
get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
// deleting a community (set counter 0 to only fetch from local db)
if object_community.is_ok() {
verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
}
// deleting a post or comment
else {
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
let object_creator =
get_post_or_comment_actor_id(&self.object, context, request_counter).await?;
verify_urls_match(&self.common.actor, &object_creator)?;
}
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object_community =
get_or_fetch_and_upsert_community(&self.object, context, request_counter).await;
// deleting a community
if let Ok(community) = object_community {
if community.local {
// repeat these checks just to be sure
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter)
.await?;
verify_mod_action(&self.common.actor, self.object.clone(), context).await?;
let mod_ =
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
community.send_delete(mod_, context).await?;
}
let deleted_community = blocking(context.pool(), move |conn| {
Community::update_deleted(conn, community.id, true)
})
.await??;
send_community_message(
deleted_community.id,
UserOperationCrud::DeleteCommunity,
context,
)
.await
}
// deleting a post or comment
else {
match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
PostOrComment::Post(post) => {
let deleted_post = blocking(context.pool(), move |conn| {
Post::update_deleted(conn, post.id, true)
})
.await??;
send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
}
PostOrComment::Comment(comment) => {
let deleted_comment = blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, comment.id, true)
})
.await??;
send_comment_message(
deleted_comment.id,
vec![],
UserOperationCrud::EditComment,
context,
)
.await
}
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}
async fn get_post_or_comment_actor_id(
object: &Url,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<Url, LemmyError> {
let actor_id =
match get_or_fetch_and_insert_post_or_comment(object, context, request_counter).await? {
PostOrComment::Post(post) => {
let creator_id = post.creator_id;
blocking(context.pool(), move |conn| Person::read(conn, creator_id))
.await??
.actor_id()
}
PostOrComment::Comment(comment) => {
let creator_id = comment.creator_id;
blocking(context.pool(), move |conn| Person::read(conn, creator_id))
.await??
.actor_id()
}
};
Ok(actor_id)
}

View file

@ -0,0 +1,2 @@
pub mod delete;
pub mod undo_delete;

View file

@ -0,0 +1,125 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
community::send_websocket_message as send_community_message,
deletion::delete::DeletePostCommentOrCommunity,
post::send_websocket_message as send_post_message,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::UndoType;
use lemmy_api_common::blocking;
use lemmy_apub::{
fetcher::{
community::get_or_fetch_and_upsert_community,
objects::get_or_fetch_and_insert_post_or_comment,
person::get_or_fetch_and_upsert_person,
},
CommunityType,
PostOrComment,
};
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};
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_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoDeletePostCommentOrCommunity {
to: PublicUrl,
object: DeletePostCommentOrCommunity,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDeletePostCommentOrCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
self.object.verify(context, request_counter).await?;
let object_community =
get_or_fetch_and_upsert_community(&self.object.object, context, request_counter).await;
// restoring a community
if object_community.is_ok() {
verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
}
// restoring a post or comment
else {
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
verify_urls_match(&self.common.actor, &self.object.common().actor)?;
}
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object_community =
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 {
// repeat these checks just to be sure
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter)
.await?;
verify_mod_action(&self.common.actor, self.object.object.clone(), context).await?;
let mod_ =
get_or_fetch_and_upsert_person(&self.common.actor, context, request_counter).await?;
community.send_undo_delete(mod_, context).await?;
}
let deleted_community = blocking(context.pool(), move |conn| {
Community::update_deleted(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 deleted_post = blocking(context.pool(), move |conn| {
Post::update_deleted(conn, post.id, false)
})
.await??;
send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
}
PostOrComment::Comment(comment) => {
let deleted_comment = blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, comment.id, false)
})
.await??;
send_comment_message(
deleted_comment.id,
vec![],
UserOperationCrud::EditComment,
context,
)
.await
}
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -18,10 +18,12 @@ use url::Url;
pub mod comment;
pub mod community;
pub mod deletion;
pub mod following;
pub mod post;
pub mod post_or_comment;
pub mod private_message;
pub mod removal;
pub mod voting;
/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
/// doesn't have a site ban.

View file

@ -1,106 +0,0 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
post::send_websocket_message as send_post_message,
verify_activity,
verify_person_in_community,
};
use activitystreams::activity::kind::DeleteType;
use lemmy_api_common::blocking;
use lemmy_apub::{
fetcher::objects::get_or_fetch_and_insert_post_or_comment,
ActorType,
PostOrComment,
};
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::{
source::{comment::Comment_, post::Post_},
Crud,
};
use lemmy_db_schema::source::{comment::Comment, person::Person, post::Post};
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DeletePostOrComment {
to: PublicUrl,
pub(in crate::activities::post_or_comment) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: DeleteType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for DeletePostOrComment {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
let object_creator =
get_post_or_comment_actor_id(&self.object, context, request_counter).await?;
verify_urls_match(&self.common.actor, &object_creator)?;
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
PostOrComment::Post(post) => {
let deleted_post = blocking(context.pool(), move |conn| {
Post::update_deleted(conn, post.id, true)
})
.await??;
send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
}
PostOrComment::Comment(comment) => {
let deleted_comment = blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, comment.id, true)
})
.await??;
send_comment_message(
deleted_comment.id,
vec![],
UserOperationCrud::EditComment,
context,
)
.await
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}
async fn get_post_or_comment_actor_id(
object: &Url,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<Url, LemmyError> {
let actor_id =
match get_or_fetch_and_insert_post_or_comment(object, context, request_counter).await? {
PostOrComment::Post(post) => {
let creator_id = post.creator_id;
blocking(context.pool(), move |conn| Person::read(conn, creator_id))
.await??
.actor_id()
}
PostOrComment::Comment(comment) => {
let creator_id = comment.creator_id;
blocking(context.pool(), move |conn| Person::read(conn, creator_id))
.await??
.actor_id()
}
};
Ok(actor_id)
}

View file

@ -1,9 +0,0 @@
pub mod delete;
pub mod dislike;
pub mod like;
pub mod remove;
pub mod undo_delete;
pub mod undo_dislike;
pub mod undo_like;
pub mod undo_remove;
mod voting;

View file

@ -1,75 +0,0 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
post::send_websocket_message as send_post_message,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::RemoveType;
use lemmy_api_common::blocking;
use lemmy_apub::{fetcher::objects::get_or_fetch_and_insert_post_or_comment, PostOrComment};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::source::{comment::Comment_, post::Post_};
use lemmy_db_schema::source::{comment::Comment, post::Post};
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemovePostOrComment {
to: PublicUrl,
pub(in crate::activities::post_or_comment) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for RemovePostOrComment {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
PostOrComment::Post(post) => {
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,
)
.await
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -1,78 +0,0 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
post::send_websocket_message as send_post_message,
post_or_comment::delete::DeletePostOrComment,
verify_activity,
verify_person_in_community,
};
use activitystreams::activity::kind::UndoType;
use lemmy_api_common::blocking;
use lemmy_apub::{fetcher::objects::get_or_fetch_and_insert_post_or_comment, PostOrComment};
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::source::{comment::Comment_, post::Post_};
use lemmy_db_schema::source::{comment::Comment, post::Post};
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoDeletePostOrComment {
to: PublicUrl,
object: DeletePostOrComment,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDeletePostOrComment {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
verify_urls_match(&self.common.actor, &self.object.common().actor)?;
self.object.verify(context, request_counter).await?;
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
match get_or_fetch_and_insert_post_or_comment(&self.object.object, context, request_counter)
.await?
{
PostOrComment::Post(post) => {
let deleted_post = blocking(context.pool(), move |conn| {
Post::update_deleted(conn, post.id, false)
})
.await??;
send_post_message(deleted_post.id, UserOperationCrud::EditPost, context).await
}
PostOrComment::Comment(comment) => {
let deleted_comment = blocking(context.pool(), move |conn| {
Comment::update_deleted(conn, comment.id, false)
})
.await??;
send_comment_message(
deleted_comment.id,
vec![],
UserOperationCrud::EditComment,
context,
)
.await
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -1,81 +0,0 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
post::send_websocket_message as send_post_message,
post_or_comment::remove::RemovePostOrComment,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::UndoType;
use lemmy_api_common::blocking;
use lemmy_apub::{fetcher::objects::get_or_fetch_and_insert_post_or_comment, PostOrComment};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
use lemmy_db_queries::source::{comment::Comment_, post::Post_};
use lemmy_db_schema::source::{comment::Comment, post::Post};
use lemmy_utils::LemmyError;
use lemmy_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoRemovePostOrComment {
to: PublicUrl,
object: RemovePostOrComment,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoRemovePostOrComment {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
verify_person_in_community(&self.common().actor, &self.cc, context, request_counter).await?;
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).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
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
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 {
&self.common
}
}

View file

@ -0,0 +1,2 @@
pub mod remove;
pub mod undo_remove;

View file

@ -0,0 +1,115 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
community::send_websocket_message as send_community_message,
post::send_websocket_message as send_post_message,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::RemoveType;
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub::{
fetcher::{
community::get_or_fetch_and_upsert_community,
objects::get_or_fetch_and_insert_post_or_comment,
},
PostOrComment,
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
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_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
// TODO: we can probably deduplicate a bunch of code between this and DeletePostCommentOrCommunity
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemovePostCommentOrCommunity {
to: PublicUrl,
pub(in crate::activities::removal) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: RemoveType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for RemovePostCommentOrCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
verify_activity(self.common())?;
let object_community =
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 a post or comment
else {
verify_person_in_community(&self.common.actor, &self.cc, context, request_counter).await?;
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).await?;
}
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object_community =
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 a post or comment
else {
match get_or_fetch_and_insert_post_or_comment(&self.object, context, request_counter).await? {
PostOrComment::Post(post) => {
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,
)
.await
}
}
}
}
fn common(&self) -> &ActivityCommonFields {
&self.common
}
}

View file

@ -0,0 +1,120 @@
use crate::activities::{
comment::send_websocket_message as send_comment_message,
community::send_websocket_message as send_community_message,
post::send_websocket_message as send_post_message,
removal::remove::RemovePostCommentOrCommunity,
verify_activity,
verify_mod_action,
verify_person_in_community,
};
use activitystreams::activity::kind::UndoType;
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_apub::{
fetcher::{
community::get_or_fetch_and_upsert_community,
objects::get_or_fetch_and_insert_post_or_comment,
},
PostOrComment,
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
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_websocket::{LemmyContext, UserOperationCrud};
use url::Url;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UndoRemovePostCommentOrCommunity {
to: PublicUrl,
object: RemovePostCommentOrCommunity,
cc: [Url; 1],
#[serde(rename = "type")]
kind: UndoType,
#[serde(flatten)]
common: ActivityCommonFields,
}
#[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoRemovePostCommentOrCommunity {
async fn verify(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
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, context, request_counter).await?;
verify_mod_action(&self.common.actor, self.cc[0].clone(), context).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
Ok(())
}
async fn receive(
&self,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
let object_community =
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 {
&self.common
}
}

View file

@ -1,7 +1,7 @@
use crate::activities::{
post_or_comment::voting::receive_like_or_dislike,
verify_activity,
verify_person_in_community,
voting::receive_like_or_dislike,
};
use activitystreams::activity::kind::DislikeType;
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};

View file

@ -1,7 +1,7 @@
use crate::activities::{
post_or_comment::voting::receive_like_or_dislike,
verify_activity,
verify_person_in_community,
voting::receive_like_or_dislike,
};
use activitystreams::activity::kind::LikeType;
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler, PublicUrl};
@ -13,7 +13,7 @@ use url::Url;
#[serde(rename_all = "camelCase")]
pub struct LikePostOrComment {
to: PublicUrl,
pub(in crate::activities::post_or_comment) object: Url,
pub(in crate::activities::voting) object: Url,
cc: [Url; 1],
#[serde(rename = "type")]
kind: LikeType,

View file

@ -20,7 +20,12 @@ use lemmy_websocket::{LemmyContext, UserOperation};
use std::ops::Deref;
use url::Url;
pub(in crate::activities::post_or_comment) async fn receive_like_or_dislike(
pub mod dislike;
pub mod like;
pub mod undo_dislike;
pub mod undo_like;
pub(in crate::activities::voting) async fn receive_like_or_dislike(
score: i16,
actor: &Url,
object: &Url,
@ -94,7 +99,7 @@ async fn like_or_dislike_post(
send_post_message(post.id, UserOperation::CreatePostLike, context).await
}
pub(in crate::activities::post_or_comment) async fn receive_undo_like_or_dislike(
pub(in crate::activities::voting) async fn receive_undo_like_or_dislike(
actor: &Url,
object: &Url,
context: &LemmyContext,

View file

@ -1,7 +1,7 @@
use crate::activities::{
post_or_comment::{dislike::DislikePostOrComment, voting::receive_undo_like_or_dislike},
verify_activity,
verify_person_in_community,
voting::{dislike::DislikePostOrComment, receive_undo_like_or_dislike},
};
use activitystreams::activity::kind::UndoType;
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};

View file

@ -1,7 +1,7 @@
use crate::activities::{
post_or_comment::{like::LikePostOrComment, voting::receive_undo_like_or_dislike},
verify_activity,
verify_person_in_community,
voting::{like::LikePostOrComment, receive_undo_like_or_dislike},
};
use activitystreams::activity::kind::UndoType;
use lemmy_apub_lib::{verify_urls_match, ActivityCommonFields, ActivityHandler, PublicUrl};

View file

@ -4,32 +4,26 @@ use crate::activities::{
add_mod::AddMod,
announce::AnnounceActivity,
block_user::BlockUserFromCommunity,
delete::DeleteCommunity,
remove::RemoveCommunity,
remove_mod::RemoveMod,
undo_block_user::UndoBlockUserFromCommunity,
undo_delete::UndoDeleteCommunity,
undo_remove::UndoRemoveCommunity,
update::UpdateCommunity,
},
deletion::{delete::DeletePostCommentOrCommunity, undo_delete::UndoDeletePostCommentOrCommunity},
following::{accept::AcceptFollowCommunity, follow::FollowCommunity, undo::UndoFollowCommunity},
post::{create::CreatePost, update::UpdatePost},
post_or_comment::{
delete::DeletePostOrComment,
dislike::DislikePostOrComment,
like::LikePostOrComment,
remove::RemovePostOrComment,
undo_delete::UndoDeletePostOrComment,
undo_dislike::UndoDislikePostOrComment,
undo_like::UndoLikePostOrComment,
undo_remove::UndoRemovePostOrComment,
},
private_message::{
create::CreatePrivateMessage,
delete::DeletePrivateMessage,
undo_delete::UndoDeletePrivateMessage,
update::UpdatePrivateMessage,
},
removal::{remove::RemovePostCommentOrCommunity, undo_remove::UndoRemovePostCommentOrCommunity},
voting::{
dislike::DislikePostOrComment,
like::LikePostOrComment,
undo_dislike::UndoDislikePostOrComment,
undo_like::UndoLikePostOrComment,
},
};
use lemmy_apub_lib::{ActivityCommonFields, ActivityHandler};
use lemmy_utils::LemmyError;
@ -60,15 +54,11 @@ pub enum GroupInboxActivities {
DislikePostOrComment(DislikePostOrComment),
UndoLikePostOrComment(UndoLikePostOrComment),
UndoDislikePostOrComment(UndoDislikePostOrComment),
DeletePostOrComment(DeletePostOrComment),
UndoDeletePostOrComment(UndoDeletePostOrComment),
RemovePostOrComment(RemovePostOrComment),
UndoRemovePostOrComment(UndoRemovePostOrComment),
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
RemovePostCommentOrCommunity(RemovePostCommentOrCommunity),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
DeleteCommunity(DeleteCommunity),
RemoveCommunity(RemoveCommunity),
UndoDeleteCommunity(UndoDeleteCommunity),
UndoRemoveCommunity(UndoRemoveCommunity),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),
@ -89,15 +79,11 @@ pub enum SharedInboxActivities {
DislikePostOrComment(DislikePostOrComment),
UndoDislikePostOrComment(UndoDislikePostOrComment),
UndoLikePostOrComment(UndoLikePostOrComment),
DeletePostOrComment(DeletePostOrComment),
UndoDeletePostOrComment(UndoDeletePostOrComment),
RemovePostOrComment(RemovePostOrComment),
UndoRemovePostOrComment(UndoRemovePostOrComment),
DeletePostCommentOrCommunity(DeletePostCommentOrCommunity),
UndoDeletePostCommentOrCommunity(UndoDeletePostCommentOrCommunity),
RemovePostCommentOrCommunity(RemovePostCommentOrCommunity),
UndoRemovePostCommentOrCommunity(UndoRemovePostCommentOrCommunity),
UpdateCommunity(Box<UpdateCommunity>),
DeleteCommunity(DeleteCommunity),
RemoveCommunity(RemoveCommunity),
UndoDeleteCommunity(UndoDeleteCommunity),
UndoRemoveCommunity(UndoRemoveCommunity),
BlockUserFromCommunity(BlockUserFromCommunity),
UndoBlockUserFromCommunity(UndoBlockUserFromCommunity),
AddMod(AddMod),