Skip to content

Commit b892f3d

Browse files
authored
remove unnecessary pictrs purge calls (#5565)
This commit removes various cases in which Lemmy would purge images from pictrs, which would in many cases not be what admins intended. pict-rs provides aliases on upload, which allows deduplicating multiple uploads of the same file in the backend, while still providing unique URLs for uploads. As Lemmy used pictrs' purge API, this meant that not only the image alias referring to removed content was deleted, all other aliases were invalidated as well. Additionally, even alias deletion would not appropriate in many of these cases, as they were lacking validation that they were exclusively used by the content they were supposed to get removed with. This implements the following changes: 1. Purging a community no longer purges the community banner or icon from pict-rs. 2. Purging a community no longer purges all images referenced in post URLs and post thumbnails within the community from pict-rs. 3. Banning a user with content removal no longer purges their profile avatar or banner from pict-rs. 4. Banning a user with content removal no longer purges images referenced in post URLs and post thumbnails for all posts they created from pict-rs. 5. Banning a user with content removal no longer purges the community banners or icons for all communities they're the top mod of from pict-rs. 6. Banning a user with content removal now deletes all media they uploaded. 7. Purging a user no longer purges their profile avatar, banner, or images referenced in post URLs and post thumbnails for all posts they created from pict-rs. All media linked to their user account will still get deleted, which was already explicitly the case in the past. 8. On an NSFW-disabled instance, receiving a post update via federation, which changes the post from not NSFW to NSFW no longer purges post URL and thumbnail from pict-rs. Some of the mentioned actions will still remove references to image URLs from the database, such as purging a community will still set its icon and banner to `NULL` in the db, but the associated images will no longer be purged from pict-rs. As this stops erasure of thumbnails, #5564 has been created to ensure tracking the person that triggered the creation of thumbnails, which will allow removing them like other images. The only remaining option to purge images attached to a post is now purging an individual post, which still erases the post URL and thumbnail from pict-rs entirely, including any other aliases. Purging and banning users with content removal will remove all aliases associated with them, which will end up deleting those images entirely when there are no other alias remaining. fixes #5560
1 parent 79f79a4 commit b892f3d

File tree

4 files changed

+8
-154
lines changed

4 files changed

+8
-154
lines changed

crates/api/src/site/purge/community.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use activitypub_federation::config::Data;
22
use actix_web::web::Json;
33
use lemmy_api_common::{
44
context::LemmyContext,
5-
request::purge_image_from_pictrs,
65
send_activity::{ActivityChannel, SendActivityData},
76
site::PurgeCommunity,
8-
utils::{is_admin, purge_image_posts_for_community},
7+
utils::is_admin,
98
SuccessResponse,
109
};
1110
use lemmy_db_schema::{
@@ -46,16 +45,6 @@ pub async fn purge_community(
4645
)
4746
.await?;
4847

49-
if let Some(banner) = &community.banner {
50-
purge_image_from_pictrs(banner, &context).await.ok();
51-
}
52-
53-
if let Some(icon) = &community.icon {
54-
purge_image_from_pictrs(icon, &context).await.ok();
55-
}
56-
57-
purge_image_posts_for_community(data.community_id, &context).await?;
58-
5948
Community::delete(&mut context.pool(), data.community_id).await?;
6049

6150
// Mod tables

crates/api_common/src/utils.rs

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -506,21 +506,6 @@ pub async fn purge_post_images(
506506
}
507507
}
508508

509-
pub async fn purge_image_posts_for_person(
510-
banned_person_id: PersonId,
511-
context: &LemmyContext,
512-
) -> LemmyResult<()> {
513-
let pool = &mut context.pool();
514-
let posts = Post::fetch_pictrs_posts_for_creator(pool, banned_person_id).await?;
515-
for post in posts {
516-
purge_post_images(post.url, post.thumbnail_url, context).await;
517-
}
518-
519-
Post::remove_pictrs_post_images_and_thumbnails_for_creator(pool, banned_person_id).await?;
520-
521-
Ok(())
522-
}
523-
524509
/// Delete a local_user's images
525510
async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
526511
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await {
@@ -538,21 +523,6 @@ async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -
538523
Ok(())
539524
}
540525

541-
pub async fn purge_image_posts_for_community(
542-
banned_community_id: CommunityId,
543-
context: &LemmyContext,
544-
) -> LemmyResult<()> {
545-
let pool = &mut context.pool();
546-
let posts = Post::fetch_pictrs_posts_for_community(pool, banned_community_id).await?;
547-
for post in posts {
548-
purge_post_images(post.url, post.thumbnail_url, context).await;
549-
}
550-
551-
Post::remove_pictrs_post_images_and_thumbnails_for_community(pool, banned_community_id).await?;
552-
553-
Ok(())
554-
}
555-
556526
/// Removes or restores user data.
557527
pub async fn remove_or_restore_user_data(
558528
mod_person_id: PersonId,
@@ -563,16 +533,9 @@ pub async fn remove_or_restore_user_data(
563533
) -> LemmyResult<()> {
564534
let pool = &mut context.pool();
565535

566-
// Only these actions are possible when removing, not restoring
536+
// These actions are only possible when removing, not restoring
567537
if removed {
568-
// Purge user images
569-
let person = Person::read(pool, banned_person_id).await?;
570-
if let Some(avatar) = person.avatar {
571-
purge_image_from_pictrs(&avatar, context).await.ok();
572-
}
573-
if let Some(banner) = person.banner {
574-
purge_image_from_pictrs(&banner, context).await.ok();
575-
}
538+
delete_local_user_images(banned_person_id, context).await?;
576539

577540
// Update the fields to None
578541
Person::update(
@@ -587,9 +550,6 @@ pub async fn remove_or_restore_user_data(
587550
)
588551
.await?;
589552

590-
// Purge image posts
591-
purge_image_posts_for_person(banned_person_id, context).await?;
592-
593553
// Communities
594554
// Remove all communities where they're the top mod
595555
// for now, remove the communities manually
@@ -613,13 +573,6 @@ pub async fn remove_or_restore_user_data(
613573
)
614574
.await?;
615575

616-
// Delete the community images
617-
if let Some(icon) = first_mod_community.community.icon {
618-
purge_image_from_pictrs(&icon, context).await.ok();
619-
}
620-
if let Some(banner) = first_mod_community.community.banner {
621-
purge_image_from_pictrs(&banner, context).await.ok();
622-
}
623576
// Update the fields to None
624577
Community::update(
625578
pool,
@@ -770,21 +723,9 @@ pub async fn remove_or_restore_user_data_in_community(
770723
pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
771724
let pool = &mut context.pool();
772725

773-
let person = Person::read(pool, person_id).await?;
774-
775726
// Delete their local images, if they're a local user
776-
delete_local_user_images(person_id, context).await.ok();
777-
778727
// No need to update avatar and banner, those are handled in Person::delete_account
779-
if let Some(avatar) = person.avatar {
780-
purge_image_from_pictrs(&avatar, context).await.ok();
781-
}
782-
if let Some(banner) = person.banner {
783-
purge_image_from_pictrs(&banner, context).await.ok();
784-
}
785-
786-
// Purge image posts
787-
purge_image_posts_for_person(person_id, context).await.ok();
728+
delete_local_user_images(person_id, context).await.ok();
788729

789730
// Comments
790731
Comment::permadelete_for_creator(pool, person_id)

crates/apub/src/objects/post.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,7 @@ use lemmy_api_common::{
2929
context::LemmyContext,
3030
plugins::{plugin_hook_after, plugin_hook_before},
3131
request::generate_post_link_metadata,
32-
utils::{
33-
check_nsfw_allowed,
34-
get_url_blocklist,
35-
process_markdown_opt,
36-
purge_post_images,
37-
slur_regex,
38-
},
32+
utils::{check_nsfw_allowed, get_url_blocklist, process_markdown_opt, slur_regex},
3933
};
4034
use lemmy_db_schema::{
4135
source::{
@@ -241,9 +235,9 @@ impl Object for ApubPost {
241235
// posts that get updated to be NSFW
242236
let block_for_nsfw = check_nsfw_allowed(page.sensitive, local_site.as_ref());
243237
if let Err(e) = block_for_nsfw {
244-
let url = url.clone().map(std::convert::Into::into);
245-
let thumbnail_url = page.image.map(|i| i.url.into());
246-
purge_post_images(url, thumbnail_url, context).await;
238+
// TODO: Remove locally generated thumbnail if one exists, depends on
239+
// https://github.com/LemmyNet/lemmy/issues/5564 to be implemented to be able to
240+
// safely do this.
247241
Post::delete_from_apub_id(&mut context.pool(), page.id.inner().clone()).await?;
248242
Err(e)?
249243
}

crates/db_schema/src/impls/post.rs

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use diesel::{
4040
NullableExpressionMethods,
4141
OptionalExtension,
4242
QueryDsl,
43-
TextExpressionMethods,
4443
};
4544
use diesel_async::RunQueryDsl;
4645
use lemmy_utils::{
@@ -210,75 +209,6 @@ impl Post {
210209
.await
211210
}
212211

213-
pub async fn fetch_pictrs_posts_for_creator(
214-
pool: &mut DbPool<'_>,
215-
for_creator_id: PersonId,
216-
) -> Result<Vec<Self>, Error> {
217-
let conn = &mut get_conn(pool).await?;
218-
let pictrs_search = "%pictrs/image%";
219-
220-
post::table
221-
.filter(post::creator_id.eq(for_creator_id))
222-
.filter(post::url.like(pictrs_search))
223-
.load::<Self>(conn)
224-
.await
225-
}
226-
227-
/// Sets the url and thumbnails fields to None
228-
pub async fn remove_pictrs_post_images_and_thumbnails_for_creator(
229-
pool: &mut DbPool<'_>,
230-
for_creator_id: PersonId,
231-
) -> Result<Vec<Self>, Error> {
232-
let conn = &mut get_conn(pool).await?;
233-
let pictrs_search = "%pictrs/image%";
234-
235-
diesel::update(
236-
post::table
237-
.filter(post::creator_id.eq(for_creator_id))
238-
.filter(post::url.like(pictrs_search)),
239-
)
240-
.set((
241-
post::url.eq::<Option<String>>(None),
242-
post::thumbnail_url.eq::<Option<String>>(None),
243-
))
244-
.get_results::<Self>(conn)
245-
.await
246-
}
247-
248-
pub async fn fetch_pictrs_posts_for_community(
249-
pool: &mut DbPool<'_>,
250-
for_community_id: CommunityId,
251-
) -> Result<Vec<Self>, Error> {
252-
let conn = &mut get_conn(pool).await?;
253-
let pictrs_search = "%pictrs/image%";
254-
post::table
255-
.filter(post::community_id.eq(for_community_id))
256-
.filter(post::url.like(pictrs_search))
257-
.load::<Self>(conn)
258-
.await
259-
}
260-
261-
/// Sets the url and thumbnails fields to None
262-
pub async fn remove_pictrs_post_images_and_thumbnails_for_community(
263-
pool: &mut DbPool<'_>,
264-
for_community_id: CommunityId,
265-
) -> Result<Vec<Self>, Error> {
266-
let conn = &mut get_conn(pool).await?;
267-
let pictrs_search = "%pictrs/image%";
268-
269-
diesel::update(
270-
post::table
271-
.filter(post::community_id.eq(for_community_id))
272-
.filter(post::url.like(pictrs_search)),
273-
)
274-
.set((
275-
post::url.eq::<Option<String>>(None),
276-
post::thumbnail_url.eq::<Option<String>>(None),
277-
))
278-
.get_results::<Self>(conn)
279-
.await
280-
}
281-
282212
pub async fn user_scheduled_post_count(
283213
person_id: PersonId,
284214
pool: &mut DbPool<'_>,

0 commit comments

Comments
 (0)