When uploading new avatar, delete old one

delete-old-avatar
Felix Ableitner 2024-03-18 11:43:52 +01:00
parent 71d8fef10e
commit 25e83c466e
5 changed files with 64 additions and 2 deletions

2
Cargo.lock generated
View File

@ -2577,6 +2577,7 @@ version = "0.19.3"
dependencies = [
"activitypub_federation",
"actix-web",
"anyhow",
"chrono",
"encoding",
"enum-map",
@ -2589,6 +2590,7 @@ dependencies = [
"lemmy_db_views_moderator",
"lemmy_utils",
"mime",
"moka",
"once_cell",
"pretty_assertions",
"regex",

View File

@ -11,7 +11,7 @@ killall -s1 lemmy_server || true
popd
pnpm i
pnpm api-test || true
pnpm api-test-user || true
killall -s1 lemmy_server || true
killall -s1 pict-rs || true

View File

@ -19,8 +19,9 @@ import {
getPost,
getComments,
fetchFunction,
alphaImage,
} from "./shared";
import { LemmyHttp, SaveUserSettings } from "lemmy-js-client";
import { LemmyHttp, SaveUserSettings, UploadImage } from "lemmy-js-client";
import { GetPosts } from "lemmy-js-client/dist/types/GetPosts";
beforeAll(setupLogins);
@ -139,3 +140,36 @@ test("Create user with Arabic name", async () => {
let alphaPerson = (await resolvePerson(alpha, apShortname)).person;
expect(alphaPerson).toBeDefined();
});
test.only("Set a new avatar, old avatar is deleted", async () => {
const listMediaRes = await alphaImage.listMedia();
expect(listMediaRes.images.length).toBe(0);
const upload_form1: UploadImage = {
image: Buffer.from("test1"),
};
const upload1 = await alphaImage.uploadImage(upload_form1);
expect(upload1.url).toBeDefined();
console.log(upload1);
let form1 = {
avatar: upload1.url
};
await saveUserSettings(alpha, form1);
const listMediaRes1 = await alphaImage.listMedia();
expect(listMediaRes1.images.length).toBe(1);
console.log(listMediaRes1);
const upload_form2: UploadImage = {
image: Buffer.from("test2"),
};
const upload2 = await alphaImage.uploadImage(upload_form2);
expect(upload2.url).toBeDefined();
let form2 = {
avatar: upload1.url
};
await saveUserSettings(alpha, form2);
// make sure only the new avatar is kept
const listMediaRes2 = await alphaImage.listMedia();
expect(listMediaRes2.images.length).toBe(1);
});

View File

@ -2,6 +2,7 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
person::SaveUserSettings,
request::delete_image_from_pictrs,
utils::{
get_url_blocklist,
local_site_to_slur_regex,
@ -14,6 +15,7 @@ use lemmy_api_common::{
use lemmy_db_schema::{
source::{
actor_language::LocalUserLanguage,
images::LocalImage,
local_user::{LocalUser, LocalUserUpdateForm},
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeUpdateForm},
person::{Person, PersonUpdateForm},
@ -40,6 +42,17 @@ pub async fn save_user_settings(
let bio = diesel_option_overwrite(
process_markdown_opt(&data.bio, &slur_regex, &url_blocklist, &context).await?,
);
if data.avatar.is_some() {
// Ignore errors because image may be stored externally.
if let Some(avatar) = &local_user_view.person.avatar {
let image = LocalImage::delete_by_url(&mut context.pool(), &avatar)
.await
.ok();
if let Some(image) = image {
delete_image_from_pictrs(&image.pictrs_alias, &image.pictrs_delete_token, &context).await?;
}
}
}
let avatar = proxy_image_link_opt_api(&data.avatar, &context).await?;
let banner = proxy_image_link_opt_api(&data.banner, &context).await?;

View File

@ -14,6 +14,8 @@ use diesel::{
QueryDsl,
};
use diesel_async::RunQueryDsl;
use once_cell::sync::Lazy;
use regex::Regex;
use url::Url;
impl LocalImage {
@ -80,6 +82,17 @@ impl LocalImage {
.execute(conn)
.await
}
pub async fn delete_by_url(pool: &mut DbPool<'_>, url: &DbUrl) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
static IMAGE_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^.*/pictrs/image/([a-z0-9-]+\.[a-z]+)$").expect("compile regex"));
let captures = IMAGE_REGEX.captures(url.as_str()).unwrap();
let alias = &captures[1];
diesel::delete(local_image::table.filter(local_image::pictrs_alias.eq(alias)))
.get_result(conn)
.await
}
}
impl RemoteImage {