Send purges to federated instances (fixes #4119) (#4398)

* Send purges to federated instances (fixes #4119)

* clippy

* review

* remove unused function

* clippy
This commit is contained in:
Nutomic 2024-01-25 15:24:09 +01:00 committed by GitHub
parent e8a52d3a5c
commit dadf8f28f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 286 additions and 179 deletions

View file

@ -75,12 +75,12 @@ pub async fn like_comment(
}
ActivityChannel::submit_activity(
SendActivityData::LikePostOrComment(
orig_comment.comment.ap_id,
local_user_view.person.clone(),
orig_comment.community,
data.score,
),
SendActivityData::LikePostOrComment {
object_id: orig_comment.comment.ap_id,
actor: local_user_view.person.clone(),
community: orig_comment.community,
score: data.score,
},
&context,
)
.await?;

View file

@ -66,12 +66,12 @@ pub async fn create_comment_report(
}
ActivityChannel::submit_activity(
SendActivityData::CreateReport(
comment_view.comment.ap_id.inner().clone(),
local_user_view.person,
comment_view.community,
data.reason.clone(),
),
SendActivityData::CreateReport {
object_id: comment_view.comment.ap_id.inner().clone(),
actor: local_user_view.person,
community: comment_view.community,
reason: data.reason.clone(),
},
&context,
)
.await?;

View file

@ -69,12 +69,12 @@ pub async fn add_mod_to_community(
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
ActivityChannel::submit_activity(
SendActivityData::AddModToCommunity(
local_user_view.person,
data.community_id,
data.person_id,
data.added,
),
SendActivityData::AddModToCommunity {
moderator: local_user_view.person,
community_id: data.community_id,
target: data.person_id,
added: data.added,
},
&context,
)
.await?;

View file

@ -92,12 +92,12 @@ pub async fn ban_from_community(
let person_view = PersonView::read(&mut context.pool(), data.person_id).await?;
ActivityChannel::submit_activity(
SendActivityData::BanFromCommunity(
local_user_view.person,
data.community_id,
person_view.person.clone(),
data.0.clone(),
),
SendActivityData::BanFromCommunity {
moderator: local_user_view.person,
community_id: data.community_id,
target: person_view.person.clone(),
data: data.0.clone(),
},
&context,
)
.await?;

View file

@ -72,11 +72,14 @@ pub async fn ban_from_site(
let person_view = PersonView::read(&mut context.pool(), data.person_id).await?;
ActivityChannel::submit_activity(
SendActivityData::BanFromSite(
local_user_view.person,
person_view.person.clone(),
data.0.clone(),
),
SendActivityData::BanFromSite {
moderator: local_user_view.person,
banned_user: person_view.person.clone(),
reason: data.reason.clone(),
remove_data: data.remove_data,
ban: data.ban,
expires: data.expires,
},
&context,
)
.await?;

View file

@ -70,12 +70,12 @@ pub async fn like_post(
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
ActivityChannel::submit_activity(
SendActivityData::LikePostOrComment(
post.ap_id,
local_user_view.person.clone(),
Community::read(&mut context.pool(), post.community_id).await?,
data.score,
),
SendActivityData::LikePostOrComment {
object_id: post.ap_id,
actor: local_user_view.person.clone(),
community: Community::read(&mut context.pool(), post.community_id).await?,
score: data.score,
},
&context,
)
.await?;

View file

@ -67,12 +67,12 @@ pub async fn create_post_report(
}
ActivityChannel::submit_activity(
SendActivityData::CreateReport(
post_view.post.ap_id.inner().clone(),
local_user_view.person,
post_view.community,
data.reason.clone(),
),
SendActivityData::CreateReport {
object_id: post_view.post.ap_id.inner().clone(),
actor: local_user_view.person,
community: post_view.community,
reason: data.reason.clone(),
},
&context,
)
.await?;

View file

@ -1,6 +1,8 @@
use actix_web::web::{Data, Json};
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
site::PurgeComment,
utils::is_admin,
SuccessResponse,
@ -12,7 +14,7 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::error::LemmyError;
#[tracing::instrument(skip(context))]
@ -26,10 +28,10 @@ pub async fn purge_comment(
let comment_id = data.comment_id;
// Read the comment to get the post_id
let comment = Comment::read(&mut context.pool(), comment_id).await?;
// Read the comment to get the post_id and community
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let post_id = comment.post_id;
let post_id = comment_view.comment.post_id;
// TODO read comments for pictrs images and purge them
@ -41,8 +43,18 @@ pub async fn purge_comment(
reason: data.reason.clone(),
post_id,
};
AdminPurgeComment::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::RemoveComment {
comment: comment_view.comment,
moderator: local_user_view.person.clone(),
community: comment_view.community,
reason: data.reason.clone(),
},
&context,
)
.await?;
Ok(Json(SuccessResponse::default()))
}

View file

@ -1,7 +1,9 @@
use actix_web::web::{Data, Json};
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
request::purge_image_from_pictrs,
send_activity::{ActivityChannel, SendActivityData},
site::PurgeCommunity,
utils::{is_admin, purge_image_posts_for_community},
SuccessResponse,
@ -25,30 +27,38 @@ pub async fn purge_community(
// Only let admin purge an item
is_admin(&local_user_view)?;
let community_id = data.community_id;
// Read the community to get its images
let community = Community::read(&mut context.pool(), community_id).await?;
let community = Community::read(&mut context.pool(), data.community_id).await?;
if let Some(banner) = community.banner {
purge_image_from_pictrs(&banner, &context).await.ok();
if let Some(banner) = &community.banner {
purge_image_from_pictrs(banner, &context).await.ok();
}
if let Some(icon) = community.icon {
purge_image_from_pictrs(&icon, &context).await.ok();
if let Some(icon) = &community.icon {
purge_image_from_pictrs(icon, &context).await.ok();
}
purge_image_posts_for_community(community_id, &context).await?;
purge_image_posts_for_community(data.community_id, &context).await?;
Community::delete(&mut context.pool(), community_id).await?;
Community::delete(&mut context.pool(), data.community_id).await?;
// Mod tables
let form = AdminPurgeCommunityForm {
admin_person_id: local_user_view.person.id,
reason: data.reason.clone(),
};
AdminPurgeCommunity::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::RemoveCommunity {
moderator: local_user_view.person.clone(),
community,
reason: data.reason.clone(),
removed: true,
},
&context,
)
.await?;
Ok(Json(SuccessResponse::default()))
}

View file

@ -1,7 +1,9 @@
use actix_web::web::{Data, Json};
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
request::delete_image_from_pictrs,
send_activity::{ActivityChannel, SendActivityData},
site::PurgePerson,
utils::is_admin,
SuccessResponse,
@ -27,9 +29,7 @@ pub async fn purge_person(
is_admin(&local_user_view)?;
// Read the person to get their images
let person_id = data.person_id;
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await {
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), data.person_id).await {
let pictrs_uploads =
LocalImage::get_all_by_local_user_id(&mut context.pool(), &local_user.local_user.id).await?;
@ -41,11 +41,11 @@ pub async fn purge_person(
}
// Clear profile data.
Person::delete_account(&mut context.pool(), person_id).await?;
Person::delete_account(&mut context.pool(), data.person_id).await?;
// Keep person record, but mark as banned to prevent login or refetching from home instance.
Person::update(
let person = Person::update(
&mut context.pool(),
person_id,
data.person_id,
&PersonUpdateForm {
banned: Some(true),
..Default::default()
@ -58,8 +58,20 @@ pub async fn purge_person(
admin_person_id: local_user_view.person.id,
reason: data.reason.clone(),
};
AdminPurgePerson::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::BanFromSite {
moderator: local_user_view.person,
banned_user: person,
reason: data.reason.clone(),
remove_data: Some(true),
ban: true,
expires: None,
},
&context,
)
.await?;
Ok(Json(SuccessResponse::default()))
}

View file

@ -1,7 +1,9 @@
use actix_web::web::{Data, Json};
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
context::LemmyContext,
request::purge_image_from_pictrs,
send_activity::{ActivityChannel, SendActivityData},
site::PurgePost,
utils::is_admin,
SuccessResponse,
@ -25,32 +27,38 @@ pub async fn purge_post(
// Only let admin purge an item
is_admin(&local_user_view)?;
let post_id = data.post_id;
// Read the post to get the community_id
let post = Post::read(&mut context.pool(), post_id).await?;
let post = Post::read(&mut context.pool(), data.post_id).await?;
// Purge image
if let Some(url) = post.url {
purge_image_from_pictrs(&url, &context).await.ok();
if let Some(url) = &post.url {
purge_image_from_pictrs(url, &context).await.ok();
}
// Purge thumbnail
if let Some(thumbnail_url) = post.thumbnail_url {
purge_image_from_pictrs(&thumbnail_url, &context).await.ok();
if let Some(thumbnail_url) = &post.thumbnail_url {
purge_image_from_pictrs(thumbnail_url, &context).await.ok();
}
let community_id = post.community_id;
Post::delete(&mut context.pool(), post_id).await?;
Post::delete(&mut context.pool(), data.post_id).await?;
// Mod tables
let form = AdminPurgePostForm {
admin_person_id: local_user_view.person.id,
reason: data.reason.clone(),
community_id,
community_id: post.community_id,
};
AdminPurgePost::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::RemovePost {
post,
moderator: local_user_view.person.clone(),
reason: data.reason.clone(),
removed: true,
},
&context,
)
.await?;
Ok(Json(SuccessResponse::default()))
}

View file

@ -1,9 +1,4 @@
use crate::{
community::BanFromCommunity,
context::LemmyContext,
person::BanPerson,
post::{DeletePost, RemovePost},
};
use crate::{community::BanFromCommunity, context::LemmyContext, post::DeletePost};
use activitypub_federation::config::Data;
use futures::future::BoxFuture;
use lemmy_db_schema::{
@ -40,26 +35,68 @@ pub enum SendActivityData {
CreatePost(Post),
UpdatePost(Post),
DeletePost(Post, Person, DeletePost),
RemovePost(Post, Person, RemovePost),
RemovePost {
post: Post,
moderator: Person,
reason: Option<String>,
removed: bool,
},
LockPost(Post, Person, bool),
FeaturePost(Post, Person, bool),
CreateComment(Comment),
UpdateComment(Comment),
DeleteComment(Comment, Person, Community),
RemoveComment(Comment, Person, Community, Option<String>),
LikePostOrComment(DbUrl, Person, Community, i16),
RemoveComment {
comment: Comment,
moderator: Person,
community: Community,
reason: Option<String>,
},
LikePostOrComment {
object_id: DbUrl,
actor: Person,
community: Community,
score: i16,
},
FollowCommunity(Community, Person, bool),
UpdateCommunity(Person, Community),
DeleteCommunity(Person, Community, bool),
RemoveCommunity(Person, Community, Option<String>, bool),
AddModToCommunity(Person, CommunityId, PersonId, bool),
BanFromCommunity(Person, CommunityId, Person, BanFromCommunity),
BanFromSite(Person, Person, BanPerson),
RemoveCommunity {
moderator: Person,
community: Community,
reason: Option<String>,
removed: bool,
},
AddModToCommunity {
moderator: Person,
community_id: CommunityId,
target: PersonId,
added: bool,
},
BanFromCommunity {
moderator: Person,
community_id: CommunityId,
target: Person,
data: BanFromCommunity,
},
BanFromSite {
moderator: Person,
banned_user: Person,
reason: Option<String>,
remove_data: Option<bool>,
ban: bool,
expires: Option<i64>,
},
CreatePrivateMessage(PrivateMessageView),
UpdatePrivateMessage(PrivateMessageView),
DeletePrivateMessage(Person, PrivateMessage, bool),
DeleteUser(Person, bool),
CreateReport(Url, Person, Community, String),
CreateReport {
object_id: Url,
actor: Person,
community: Community,
reason: String,
},
}
// TODO: instead of static, move this into LemmyContext. make sure that stopping the process with

View file

@ -71,12 +71,12 @@ pub async fn remove_comment(
let updated_comment_id = updated_comment.id;
ActivityChannel::submit_activity(
SendActivityData::RemoveComment(
updated_comment,
local_user_view.person.clone(),
orig_comment.community,
data.reason.clone(),
),
SendActivityData::RemoveComment {
comment: updated_comment,
moderator: local_user_view.person.clone(),
community: orig_comment.community,
reason: data.reason.clone(),
},
&context,
)
.await?;

View file

@ -58,12 +58,12 @@ pub async fn remove_community(
ModRemoveCommunity::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::RemoveCommunity(
local_user_view.person.clone(),
SendActivityData::RemoveCommunity {
moderator: local_user_view.person.clone(),
community,
data.reason.clone(),
data.removed,
),
reason: data.reason.clone(),
removed: data.removed,
},
&context,
)
.await?;

View file

@ -57,7 +57,12 @@ pub async fn remove_post(
ModRemovePost::create(&mut context.pool(), &form).await?;
ActivityChannel::submit_activity(
SendActivityData::RemovePost(post, local_user_view.person.clone(), data.0),
SendActivityData::RemovePost {
post,
moderator: local_user_view.person.clone(),
reason: data.reason.clone(),
removed: data.removed,
},
&context,
)
.await?;

View file

@ -14,7 +14,6 @@ use chrono::{DateTime, Utc};
use lemmy_api_common::{
community::BanFromCommunity,
context::LemmyContext,
person::BanPerson,
utils::check_expire_time,
};
use lemmy_db_schema::{
@ -133,23 +132,26 @@ async fn generate_cc(
}
pub(crate) async fn send_ban_from_site(
mod_: Person,
moderator: Person,
banned_user: Person,
data: BanPerson,
reason: Option<String>,
remove_data: Option<bool>,
ban: bool,
expires: Option<i64>,
context: Data<LemmyContext>,
) -> Result<(), LemmyError> {
let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into());
let expires = check_expire_time(data.expires)?;
let expires = check_expire_time(expires)?;
// if the action affects a local user, federate to other instances
if banned_user.local {
if data.ban {
if ban {
BlockUser::send(
&site,
&banned_user.into(),
&mod_.into(),
data.remove_data.unwrap_or(false),
data.reason.clone(),
&moderator.into(),
remove_data.unwrap_or(false),
reason.clone(),
expires,
&context,
)
@ -158,8 +160,8 @@ pub(crate) async fn send_ban_from_site(
UndoBlockUser::send(
&site,
&banned_user.into(),
&mod_.into(),
data.reason.clone(),
&moderator.into(),
reason.clone(),
&context,
)
.await

View file

@ -29,7 +29,6 @@ use activitypub_federation::{
};
use lemmy_api_common::{context::LemmyContext, utils::purge_user_account};
use lemmy_db_schema::{
newtypes::CommunityId,
source::{
activity::ActivitySendTargets,
comment::{Comment, CommentUpdateForm},
@ -78,38 +77,6 @@ pub(crate) async fn send_apub_delete_in_community(
.await
}
/// 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(crate) async fn send_apub_delete_in_community_new(
actor: Person,
community_id: CommunityId,
object: DeletableObjects,
reason: Option<String>,
deleted: bool,
context: Data<LemmyContext>,
) -> Result<(), LemmyError> {
let community = Community::read(&mut context.pool(), community_id).await?;
let actor = ApubPerson::from(actor);
let is_mod_action = reason.is_some();
let activity = if deleted {
let delete = Delete::new(&actor, object, public(), Some(&community), reason, &context)?;
AnnouncableActivities::Delete(delete)
} else {
let undo = UndoDelete::new(&actor, object, public(), Some(&community), reason, &context)?;
AnnouncableActivities::UndoDelete(undo)
};
send_activity_in_community(
activity,
&actor,
&community.into(),
ActivitySendTargets::empty(),
is_mod_action,
&context,
)
.await
}
#[tracing::instrument(skip_all)]
pub(crate) async fn send_apub_delete_private_message(
actor: &ApubPerson,

View file

@ -10,7 +10,6 @@ use crate::{
create_or_update::private_message::send_create_or_update_pm,
deletion::{
send_apub_delete_in_community,
send_apub_delete_in_community_new,
send_apub_delete_private_message,
send_apub_delete_user,
DeletableObjects,
@ -35,9 +34,12 @@ use lemmy_api_common::{
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
};
use lemmy_db_schema::source::{
use lemmy_db_schema::{
source::{
activity::{ActivitySendTargets, ActorType, SentActivity, SentActivityForm},
community::Community,
},
traits::Crud,
};
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
@ -246,24 +248,31 @@ pub async fn match_outgoing_activities(
CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Update, context).await
}
DeletePost(post, person, data) => {
send_apub_delete_in_community_new(
let community = Community::read(&mut context.pool(), post.community_id).await?;
send_apub_delete_in_community(
person,
post.community_id,
community,
DeletableObjects::Post(post.into()),
None,
data.deleted,
context,
&context,
)
.await
}
RemovePost(post, person, data) => {
send_apub_delete_in_community_new(
person,
post.community_id,
RemovePost {
post,
moderator,
reason,
removed,
} => {
let community = Community::read(&mut context.pool(), post.community_id).await?;
send_apub_delete_in_community(
moderator,
community,
DeletableObjects::Post(post.into()),
data.reason.or_else(|| Some(String::new())),
data.removed,
context,
reason.or_else(|| Some(String::new())),
removed,
&context,
)
.await
}
@ -282,15 +291,25 @@ pub async fn match_outgoing_activities(
let deletable = DeletableObjects::Comment(comment.into());
send_apub_delete_in_community(actor, community, deletable, None, is_deleted, &context).await
}
RemoveComment(comment, actor, community, reason) => {
RemoveComment {
comment,
moderator,
community,
reason,
} => {
let is_removed = comment.removed;
let deletable = DeletableObjects::Comment(comment.into());
send_apub_delete_in_community(actor, community, deletable, reason, is_removed, &context)
send_apub_delete_in_community(
moderator, community, deletable, reason, is_removed, &context,
)
.await
}
LikePostOrComment(object_id, person, community, score) => {
send_like_activity(object_id, person, community, score, context).await
}
LikePostOrComment {
object_id,
actor,
community,
score,
} => send_like_activity(object_id, actor, community, score, context).await,
FollowCommunity(community, person, follow) => {
send_follow_community(community, person, follow, &context).await
}
@ -299,10 +318,15 @@ pub async fn match_outgoing_activities(
let deletable = DeletableObjects::Community(community.clone().into());
send_apub_delete_in_community(actor, community, deletable, None, removed, &context).await
}
RemoveCommunity(actor, community, reason, removed) => {
RemoveCommunity {
moderator,
community,
reason,
removed,
} => {
let deletable = DeletableObjects::Community(community.clone().into());
send_apub_delete_in_community(
actor,
moderator,
community,
deletable,
reason.clone().or_else(|| Some(String::new())),
@ -311,13 +335,37 @@ pub async fn match_outgoing_activities(
)
.await
}
AddModToCommunity(actor, community_id, updated_mod_id, added) => {
send_add_mod_to_community(actor, community_id, updated_mod_id, added, context).await
AddModToCommunity {
moderator,
community_id,
target,
added,
} => send_add_mod_to_community(moderator, community_id, target, added, context).await,
BanFromCommunity {
moderator,
community_id,
target,
data,
} => send_ban_from_community(moderator, community_id, target, data, context).await,
BanFromSite {
moderator,
banned_user,
reason,
remove_data,
ban,
expires,
} => {
send_ban_from_site(
moderator,
banned_user,
reason,
remove_data,
ban,
expires,
context,
)
.await
}
BanFromCommunity(mod_, community_id, target, data) => {
send_ban_from_community(mod_, community_id, target, data, context).await
}
BanFromSite(mod_, target, data) => send_ban_from_site(mod_, target, data, context).await,
CreatePrivateMessage(pm) => {
send_create_or_update_pm(pm, CreateOrUpdateType::Create, context).await
}
@ -328,9 +376,12 @@ pub async fn match_outgoing_activities(
send_apub_delete_private_message(&person.into(), pm, deleted, context).await
}
DeleteUser(person, remove_data) => send_apub_delete_user(person, remove_data, context).await,
CreateReport(url, actor, community, reason) => {
Report::send(ObjectId::from(url), actor, community, reason, context).await
}
CreateReport {
object_id,
actor,
community,
reason,
} => Report::send(ObjectId::from(object_id), actor, community, reason, context).await,
}
};
fed_task.await?;