From 705703f5396c0d34bceba61fdfc2eec5668856cb Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 9 Jan 2025 15:23:06 +0100 Subject: [PATCH] add delete endpoints --- api_tests/package.json | 2 +- api_tests/pnpm-lock.yaml | 10 +- crates/routes/src/images/delete.rs | 142 +++++++++++++++++++++++++++++ crates/routes/src/images/mod.rs | 33 +------ src/api_routes_v3.rs | 2 +- src/api_routes_v4.rs | 17 +++- 6 files changed, 166 insertions(+), 40 deletions(-) create mode 100644 crates/routes/src/images/delete.rs diff --git a/api_tests/package.json b/api_tests/package.json index b75ddbd52..39deef22f 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -28,7 +28,7 @@ "eslint": "^9.14.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.5.0", - "lemmy-js-client": "0.20.0-image-api-rework.7", + "lemmy-js-client": "0.20.0-image-api-rework.8", "prettier": "^3.2.5", "ts-jest": "^29.1.0", "typescript": "^5.5.4", diff --git a/api_tests/pnpm-lock.yaml b/api_tests/pnpm-lock.yaml index 01bc71cb6..5aaa59d2c 100644 --- a/api_tests/pnpm-lock.yaml +++ b/api_tests/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^29.5.0 version: 29.7.0(@types/node@22.9.0) lemmy-js-client: - specifier: 0.20.0-image-api-rework.7 - version: 0.20.0-image-api-rework.7 + specifier: 0.20.0-image-api-rework.8 + version: 0.20.0-image-api-rework.8 prettier: specifier: ^3.2.5 version: 3.3.3 @@ -1167,8 +1167,8 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - lemmy-js-client@0.20.0-image-api-rework.7: - resolution: {integrity: sha512-zZVOu8l9ctwEof71/DDkg/pwwBercLJIJja7KT1WxYS2pG6Hng9bD0+VDesbdvacCltFDbbEvk8pgJs3ES4OIQ==} + lemmy-js-client@0.20.0-image-api-rework.8: + resolution: {integrity: sha512-Ns/ayfCSm2lHbdAU1tGIZSx6kJ2ZeS7UiXlPuH0IzHQSi8Yuyzj3srDCyHpE6Td3pmXbQlt9N1ziPE4KeRJ3CA==} leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -3077,7 +3077,7 @@ snapshots: kleur@3.0.3: {} - lemmy-js-client@0.20.0-image-api-rework.7: {} + lemmy-js-client@0.20.0-image-api-rework.8: {} leven@3.1.0: {} diff --git a/crates/routes/src/images/delete.rs b/crates/routes/src/images/delete.rs new file mode 100644 index 000000000..82f48b736 --- /dev/null +++ b/crates/routes/src/images/delete.rs @@ -0,0 +1,142 @@ +use super::utils::{delete_old_image, PICTRS_CLIENT}; +use actix_web::web::*; +use lemmy_api_common::{ + context::LemmyContext, + image::{CommunityIdQuery, DeleteImageParams}, + utils::{is_admin, is_mod_or_admin}, + SuccessResponse, +}; +use lemmy_db_schema::{ + source::{ + community::{Community, CommunityUpdateForm}, + images::LocalImage, + person::{Person, PersonUpdateForm}, + site::{Site, SiteUpdateForm}, + }, + traits::Crud, +}; +use lemmy_db_views::structs::LocalUserView; +use lemmy_utils::error::LemmyResult; + +pub async fn delete_site_icon( + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + let site = Site::read_local(&mut context.pool()).await?; + is_admin(&local_user_view)?; + + delete_old_image(&site.icon, &context).await?; + + let form = SiteUpdateForm { + icon: Some(None), + ..Default::default() + }; + Site::update(&mut context.pool(), site.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} +pub async fn delete_site_banner( + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + let site = Site::read_local(&mut context.pool()).await?; + is_admin(&local_user_view)?; + + delete_old_image(&site.banner, &context).await?; + + let form = SiteUpdateForm { + banner: Some(None), + ..Default::default() + }; + Site::update(&mut context.pool(), site.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} + +pub async fn delete_community_icon( + data: Json, + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + let community = Community::read(&mut context.pool(), data.id).await?; + is_mod_or_admin(&mut context.pool(), &local_user_view.person, community.id).await?; + + delete_old_image(&community.icon, &context).await?; + + let form = CommunityUpdateForm { + icon: Some(None), + ..Default::default() + }; + Community::update(&mut context.pool(), community.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} + +pub async fn delete_community_banner( + data: Json, + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + let community = Community::read(&mut context.pool(), data.id).await?; + is_mod_or_admin(&mut context.pool(), &local_user_view.person, community.id).await?; + + delete_old_image(&community.icon, &context).await?; + + let form = CommunityUpdateForm { + icon: Some(None), + ..Default::default() + }; + Community::update(&mut context.pool(), community.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} + +pub async fn delete_user_avatar( + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + delete_old_image(&local_user_view.person.avatar, &context).await?; + + let form = PersonUpdateForm { + avatar: Some(None), + ..Default::default() + }; + Person::update(&mut context.pool(), local_user_view.person.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} + +pub async fn delete_user_banner( + context: Data, + local_user_view: LocalUserView, +) -> LemmyResult> { + delete_old_image(&local_user_view.person.banner, &context).await?; + + let form = PersonUpdateForm { + banner: Some(None), + ..Default::default() + }; + Person::update(&mut context.pool(), local_user_view.person.id, &form).await?; + + Ok(Json(SuccessResponse::default())) +} + +// TODO: get rid of delete tokens and allow deletion by admin or uploader +pub async fn delete_image( + data: Json, + context: Data, + // require login + _local_user_view: LocalUserView, +) -> LemmyResult> { + let pictrs_config = context.settings().pictrs()?; + let url = format!( + "{}image/delete/{}/{}", + pictrs_config.url, &data.token, &data.filename + ); + + PICTRS_CLIENT.delete(url).send().await?.error_for_status()?; + + LocalImage::delete_by_alias(&mut context.pool(), &data.filename).await?; + + Ok(Json(SuccessResponse::default())) +} diff --git a/crates/routes/src/images/mod.rs b/crates/routes/src/images/mod.rs index 1d3260e44..f4297e17e 100644 --- a/crates/routes/src/images/mod.rs +++ b/crates/routes/src/images/mod.rs @@ -1,42 +1,13 @@ use actix_web::web::*; -use lemmy_api_common::{context::LemmyContext, image::DeleteImageParams, SuccessResponse}; -use lemmy_db_schema::source::images::LocalImage; -use lemmy_db_views::structs::LocalUserView; +use lemmy_api_common::{context::LemmyContext, SuccessResponse}; use lemmy_utils::error::LemmyResult; use utils::PICTRS_CLIENT; +pub mod delete; pub mod download; pub mod upload; mod utils; -pub async fn delete_community_icon( - data: Json, - context: Data, - local_user_view: LocalUserView, -) -> LemmyResult> { - todo!() -} - -// TODO: get rid of delete tokens and allow deletion by admin or uploader -pub async fn delete_image( - data: Json, - context: Data, - // require login - _local_user_view: LocalUserView, -) -> LemmyResult> { - let pictrs_config = context.settings().pictrs()?; - let url = format!( - "{}image/delete/{}/{}", - pictrs_config.url, &data.token, &data.filename - ); - - PICTRS_CLIENT.delete(url).send().await?.error_for_status()?; - - LocalImage::delete_by_alias(&mut context.pool(), &data.filename).await?; - - Ok(Json(SuccessResponse::default())) -} - pub async fn pictrs_health(context: Data) -> LemmyResult> { let pictrs_config = context.settings().pictrs()?; let url = format!("{}healthz", pictrs_config.url); diff --git a/src/api_routes_v3.rs b/src/api_routes_v3.rs index 36d7ad69a..817e3f6a1 100644 --- a/src/api_routes_v3.rs +++ b/src/api_routes_v3.rs @@ -124,7 +124,7 @@ use lemmy_apub::api::{ user_settings_backup::{export_settings, import_settings}, }; use lemmy_routes::images::{ - delete_image, + delete::delete_image, download::{get_image, image_proxy}, pictrs_health, upload::upload_image, diff --git a/src/api_routes_v4.rs b/src/api_routes_v4.rs index 3572f8ebf..8cbe11c19 100644 --- a/src/api_routes_v4.rs +++ b/src/api_routes_v4.rs @@ -150,7 +150,15 @@ use lemmy_apub::api::{ user_settings_backup::{export_settings, import_settings}, }; use lemmy_routes::images::{ - delete_image, + delete::{ + delete_community_banner, + delete_community_icon, + delete_image, + delete_site_banner, + delete_site_icon, + delete_user_avatar, + delete_user_banner, + }, download::{get_image, image_proxy}, pictrs_health, upload::{ @@ -176,7 +184,9 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) { .route("", post().to(create_site)) .route("", put().to(update_site)) .route("/icon", post().to(upload_site_icon)) - .route("/banner", post().to(upload_site_banner)), + .route("/icon", delete().to(delete_site_icon)) + .route("/banner", post().to(upload_site_banner)) + .route("/banner", delete().to(delete_site_banner)), ) .route("/modlog", get().to(get_mod_log)) .service( @@ -209,6 +219,7 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) { .route("/icon", post().to(upload_community_icon)) .route("/icon", delete().to(delete_community_icon)) .route("/banner", post().to(upload_community_banner)) + .route("/banner", delete().to(delete_community_banner)) .service( scope("/pending_follows") .route("/count", get().to(get_pending_follows_count)) @@ -327,7 +338,9 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) { .route("/list_logins", get().to(list_logins)) .route("/validate_auth", get().to(validate_auth)) .route("/avatar", post().to(upload_user_avatar)) + .route("/avatar", delete().to(delete_user_avatar)) .route("/banner", post().to(upload_user_banner)) + .route("/banner", delete().to(delete_user_banner)) .service( scope("/block") .route("/person", post().to(user_block_person))