From 6e4fd3da369dc72d07451bc7718585a6fc7845cc Mon Sep 17 00:00:00 2001 From: trisua Date: Sun, 7 Sep 2025 11:06:03 -0400 Subject: [PATCH] add: uploads in post quotes --- Cargo.lock | 4 +- .../public/html/communities/create_post.lisp | 1 + crates/app/src/public/html/components.lisp | 2 +- crates/app/src/public/js/me.js | 23 +++++-- .../src/routes/api/v1/communities/posts.rs | 68 +++++++++++++++++-- crates/core/Cargo.toml | 2 +- 6 files changed, 84 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d99ebb3..c93a829 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3452,7 +3452,7 @@ dependencies = [ "serde", "serde_json", "tera", - "tetratto-core 16.0.2", + "tetratto-core 16.0.3", "tetratto-l10n 12.0.0", "tetratto-shared 12.0.6", "tokio", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "tetratto-core" -version = "16.0.2" +version = "16.0.3" dependencies = [ "async-recursion", "base16ct", diff --git a/crates/app/src/public/html/communities/create_post.lisp b/crates/app/src/public/html/communities/create_post.lisp index 7e3be37..938f019 100644 --- a/crates/app/src/public/html/communities/create_post.lisp +++ b/crates/app/src/public/html/communities/create_post.lisp @@ -361,6 +361,7 @@ false, document.getElementById(\"community_to_post_to\") .selectedOptions[0].getAttribute(\"is_stack\") === \"true\", + e.target.file_picker ? e.target.file_picker.files : [], ]); // update settings diff --git a/crates/app/src/public/html/components.lisp b/crates/app/src/public/html/components.lisp index 28ddeb7..53e316d 100644 --- a/crates/app/src/public/html/components.lisp +++ b/crates/app/src/public/html/components.lisp @@ -1494,7 +1494,7 @@ (text "{% macro create_post_options() -%}") (div ("class" "flex gap_2 flex_wrap") - (text "{{ components::emoji_picker(element_id=\"content\", render_dialog=true) }} {% if not quoting -%} {% if is_supporter -%} {{ components::file_picker(files_list_id=\"files_list\") }} {%- endif %} {%- endif %}") + (text "{{ components::emoji_picker(element_id=\"content\", render_dialog=true) }} {% if is_supporter -%} {{ components::file_picker(files_list_id=\"files_list\") }} {%- endif %}") (button ("class" "small square lowered") diff --git a/crates/app/src/public/js/me.js b/crates/app/src/public/js/me.js index e9b3649..beb74d6 100644 --- a/crates/app/src/public/js/me.js +++ b/crates/app/src/public/js/me.js @@ -311,19 +311,30 @@ community, do_not_redirect = false, is_stack = false, + uploads = [], ) => { await trigger("atto::debounce", ["posts::create"]); return new Promise((resolve, _) => { - fetch(`/api/v1/posts/${id}/repost`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ + // create body + const body = new FormData(); + + for (const file of uploads) { + body.append(file.name, file); + } + + body.append( + "body", + JSON.stringify({ content, community: !is_stack ? community : "0", stack: is_stack ? community : "0", }), + ); + + // send + fetch(`/api/v1/posts/${id}/repost`, { + method: "POST", + body, }) .then((res) => res.json()) .then((res) => { diff --git a/crates/app/src/routes/api/v1/communities/posts.rs b/crates/app/src/routes/api/v1/communities/posts.rs index e22a7ff..43e2fb3 100644 --- a/crates/app/src/routes/api/v1/communities/posts.rs +++ b/crates/app/src/routes/api/v1/communities/posts.rs @@ -241,7 +241,7 @@ pub async fn create_repost_request( jar: CookieJar, Extension(data): Extension, Path(id): Path, - Json(req): Json, + JsonMultipart(images, req): JsonMultipart, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreatePosts) { @@ -264,13 +264,69 @@ pub async fn create_repost_request( Err(e) => return Json(Error::MiscError(e.to_string()).into()), }; + // check sizes + for img in &images { + if img.len() > MAXIMUM_FILE_SIZE { + return Json(Error::FileTooLarge.into()); + } + } + + // create uploads + for _ in 0..images.len() { + props.uploads.push( + match data + .2 + .create_upload(MediaUpload::new( + MediaType::Webp, + props.owner, + "post_media".to_string(), + )) + .await + { + Ok(u) => u.id, + Err(e) => return Json(Error::MiscError(e.to_string()).into()), + }, + ); + } + // ... + let uploads = props.uploads.clone(); match data.create_post(props).await { - Ok(id) => Json(ApiReturn { - ok: true, - message: "Post reposted".to_string(), - payload: Some(id.to_string()), - }), + Ok(id) => { + // write to uploads + for (i, upload_id) in uploads.iter().enumerate() { + let image = match images.get(i) { + Some(img) => img, + None => { + if let Err(e) = data.2.delete_upload(*upload_id).await { + return Json(Error::MiscError(e.to_string()).into()); + } + + continue; + } + }; + + let upload = match data.2.get_upload_by_id(*upload_id).await { + Ok(u) => u, + Err(e) => return Json(Error::MiscError(e.to_string()).into()), + }; + + if let Err(e) = save_webp_buffer( + &upload.path(&data.2.0.0.directory).to_string(), + image.to_vec(), + None, + ) { + return Json(Error::MiscError(e.to_string()).into()); + } + } + + // ... + Json(ApiReturn { + ok: true, + message: "Post reposted".to_string(), + payload: Some(id.to_string()), + }) + } Err(e) => Json(e.into()), } } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 2a3f47b..a001303 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tetratto-core" description = "The core behind Tetratto" -version = "16.0.2" +version = "16.0.3" edition = "2024" readme = "../../README.md" authors.workspace = true