Skip to content

Commit c20e198

Browse files
committed
remove unnecessary pictrs purge calls
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. 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. Some of the mentioned actions will still remove references to image URLs from the database, such as banning a user with content removal setting their avatar and profile banner to `NULL` in the db, which prevents them from being displayed on their profile. As this stops erasure of thumbnails, LemmyNet#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 users will remove all aliases associated with them, which will end up deleting those images entirely when there are no other alias remaining. backports LemmyNet#5565 to 0.19 LemmyNet#5565 LemmyNet@988638d
1 parent 3d98f81 commit c20e198

File tree

3 files changed

+4
-169
lines changed

3 files changed

+4
-169
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::{
@@ -50,16 +49,6 @@ pub async fn purge_community(
5049
)
5150
.await?;
5251

53-
if let Some(banner) = &community.banner {
54-
purge_image_from_pictrs(banner, &context).await.ok();
55-
}
56-
57-
if let Some(icon) = &community.icon {
58-
purge_image_from_pictrs(icon, &context).await.ok();
59-
}
60-
61-
purge_image_posts_for_community(data.community_id, &context).await?;
62-
6352
Community::delete(&mut context.pool(), data.community_id).await?;
6453

6554
// Mod tables

crates/api_common/src/utils.rs

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
use crate::{
22
context::LemmyContext,
3-
request::{
4-
delete_image_from_pictrs,
5-
fetch_pictrs_proxied_image_details,
6-
purge_image_from_pictrs,
7-
},
3+
request::{delete_image_from_pictrs, fetch_pictrs_proxied_image_details},
84
site::{FederatedInstances, InstanceWithFederationState},
95
};
106
use chrono::{DateTime, Days, Local, TimeZone, Utc};
@@ -646,26 +642,6 @@ pub async fn read_site_for_actor(
646642
Ok(site)
647643
}
648644

649-
pub async fn purge_image_posts_for_person(
650-
banned_person_id: PersonId,
651-
context: &LemmyContext,
652-
) -> LemmyResult<()> {
653-
let pool = &mut context.pool();
654-
let posts = Post::fetch_pictrs_posts_for_creator(pool, banned_person_id).await?;
655-
for post in posts {
656-
if let Some(url) = post.url {
657-
purge_image_from_pictrs(&url, context).await.ok();
658-
}
659-
if let Some(thumbnail_url) = post.thumbnail_url {
660-
purge_image_from_pictrs(&thumbnail_url, context).await.ok();
661-
}
662-
}
663-
664-
Post::remove_pictrs_post_images_and_thumbnails_for_creator(pool, banned_person_id).await?;
665-
666-
Ok(())
667-
}
668-
669645
/// Delete a local_user's images
670646
async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
671647
if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await {
@@ -687,41 +663,11 @@ async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -
687663
Ok(())
688664
}
689665

690-
pub async fn purge_image_posts_for_community(
691-
banned_community_id: CommunityId,
692-
context: &LemmyContext,
693-
) -> LemmyResult<()> {
694-
let pool = &mut context.pool();
695-
let posts = Post::fetch_pictrs_posts_for_community(pool, banned_community_id).await?;
696-
for post in posts {
697-
if let Some(url) = post.url {
698-
purge_image_from_pictrs(&url, context).await.ok();
699-
}
700-
if let Some(thumbnail_url) = post.thumbnail_url {
701-
purge_image_from_pictrs(&thumbnail_url, context).await.ok();
702-
}
703-
}
704-
705-
Post::remove_pictrs_post_images_and_thumbnails_for_community(pool, banned_community_id).await?;
706-
707-
Ok(())
708-
}
709-
710666
pub async fn remove_user_data(
711667
banned_person_id: PersonId,
712668
context: &LemmyContext,
713669
) -> LemmyResult<()> {
714670
let pool = &mut context.pool();
715-
// Purge user images
716-
let person = Person::read(pool, banned_person_id)
717-
.await?
718-
.ok_or(LemmyErrorType::CouldntFindPerson)?;
719-
if let Some(avatar) = person.avatar {
720-
purge_image_from_pictrs(&avatar, context).await.ok();
721-
}
722-
if let Some(banner) = person.banner {
723-
purge_image_from_pictrs(&banner, context).await.ok();
724-
}
725671

726672
// Update the fields to None
727673
Person::update(
@@ -739,9 +685,6 @@ pub async fn remove_user_data(
739685
// Posts
740686
Post::update_removed_for_creator(pool, banned_person_id, None, true).await?;
741687

742-
// Purge image posts
743-
purge_image_posts_for_person(banned_person_id, context).await?;
744-
745688
// Communities
746689
// Remove all communities where they're the top mod
747690
// for now, remove the communities manually
@@ -765,13 +708,6 @@ pub async fn remove_user_data(
765708
)
766709
.await?;
767710

768-
// Delete the community images
769-
if let Some(icon) = first_mod_community.community.icon {
770-
purge_image_from_pictrs(&icon, context).await.ok();
771-
}
772-
if let Some(banner) = first_mod_community.community.banner {
773-
purge_image_from_pictrs(&banner, context).await.ok();
774-
}
775711
// Update the fields to None
776712
Community::update(
777713
pool,
@@ -828,23 +764,9 @@ pub async fn remove_user_data_in_community(
828764
pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
829765
let pool = &mut context.pool();
830766

831-
let person = Person::read(pool, person_id)
832-
.await?
833-
.ok_or(LemmyErrorType::CouldntFindPerson)?;
834-
835767
// Delete their local images, if they're a local user
836-
delete_local_user_images(person_id, context).await.ok();
837-
838768
// No need to update avatar and banner, those are handled in Person::delete_account
839-
if let Some(avatar) = person.avatar {
840-
purge_image_from_pictrs(&avatar, context).await.ok();
841-
}
842-
if let Some(banner) = person.banner {
843-
purge_image_from_pictrs(&banner, context).await.ok();
844-
}
845-
846-
// Purge image posts
847-
purge_image_posts_for_person(person_id, context).await.ok();
769+
delete_local_user_images(person_id, context).await.ok();
848770

849771
// Comments
850772
Comment::permadelete_for_creator(pool, person_id)

crates/db_schema/src/impls/post.rs

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,7 @@ use crate::{
2929
};
3030
use ::url::Url;
3131
use chrono::{DateTime, Utc};
32-
use diesel::{
33-
dsl::insert_into,
34-
result::Error,
35-
DecoratableTarget,
36-
ExpressionMethods,
37-
QueryDsl,
38-
TextExpressionMethods,
39-
};
32+
use diesel::{dsl::insert_into, result::Error, DecoratableTarget, ExpressionMethods, QueryDsl};
4033
use diesel_async::RunQueryDsl;
4134
use std::collections::HashSet;
4235

@@ -173,75 +166,6 @@ impl Post {
173166
.await
174167
.optional()
175168
}
176-
177-
pub async fn fetch_pictrs_posts_for_creator(
178-
pool: &mut DbPool<'_>,
179-
for_creator_id: PersonId,
180-
) -> Result<Vec<Self>, Error> {
181-
let conn = &mut get_conn(pool).await?;
182-
let pictrs_search = "%pictrs/image%";
183-
184-
post::table
185-
.filter(post::creator_id.eq(for_creator_id))
186-
.filter(post::url.like(pictrs_search))
187-
.load::<Self>(conn)
188-
.await
189-
}
190-
191-
/// Sets the url and thumbnails fields to None
192-
pub async fn remove_pictrs_post_images_and_thumbnails_for_creator(
193-
pool: &mut DbPool<'_>,
194-
for_creator_id: PersonId,
195-
) -> Result<Vec<Self>, Error> {
196-
let conn = &mut get_conn(pool).await?;
197-
let pictrs_search = "%pictrs/image%";
198-
199-
diesel::update(
200-
post::table
201-
.filter(post::creator_id.eq(for_creator_id))
202-
.filter(post::url.like(pictrs_search)),
203-
)
204-
.set((
205-
post::url.eq::<Option<String>>(None),
206-
post::thumbnail_url.eq::<Option<String>>(None),
207-
))
208-
.get_results::<Self>(conn)
209-
.await
210-
}
211-
212-
pub async fn fetch_pictrs_posts_for_community(
213-
pool: &mut DbPool<'_>,
214-
for_community_id: CommunityId,
215-
) -> Result<Vec<Self>, Error> {
216-
let conn = &mut get_conn(pool).await?;
217-
let pictrs_search = "%pictrs/image%";
218-
post::table
219-
.filter(post::community_id.eq(for_community_id))
220-
.filter(post::url.like(pictrs_search))
221-
.load::<Self>(conn)
222-
.await
223-
}
224-
225-
/// Sets the url and thumbnails fields to None
226-
pub async fn remove_pictrs_post_images_and_thumbnails_for_community(
227-
pool: &mut DbPool<'_>,
228-
for_community_id: CommunityId,
229-
) -> Result<Vec<Self>, Error> {
230-
let conn = &mut get_conn(pool).await?;
231-
let pictrs_search = "%pictrs/image%";
232-
233-
diesel::update(
234-
post::table
235-
.filter(post::community_id.eq(for_community_id))
236-
.filter(post::url.like(pictrs_search)),
237-
)
238-
.set((
239-
post::url.eq::<Option<String>>(None),
240-
post::thumbnail_url.eq::<Option<String>>(None),
241-
))
242-
.get_results::<Self>(conn)
243-
.await
244-
}
245169
}
246170

247171
#[async_trait]

0 commit comments

Comments
 (0)