From c656465e280172b9acd6344c385398ed91cb84b2 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 3 Jan 2025 05:02:20 -0500 Subject: [PATCH 1/5] Fix contradicting filters. (#5281) --- crates/apub/src/api/list_comments.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/apub/src/api/list_comments.rs b/crates/apub/src/api/list_comments.rs index 3e7a2f4eb..05195b3af 100644 --- a/crates/apub/src/api/list_comments.rs +++ b/crates/apub/src/api/list_comments.rs @@ -9,7 +9,7 @@ use actix_web::web::{Json, Query}; use lemmy_api_common::{ comment::{GetComments, GetCommentsResponse}, context::LemmyContext, - utils::check_private_instance, + utils::{check_conflicting_like_filters, check_private_instance}, }; use lemmy_db_schema::{ source::{comment::Comment, community::Community}, @@ -19,7 +19,7 @@ use lemmy_db_views::{ comment_view::CommentQuery, structs::{LocalUserView, SiteView}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn list_comments( @@ -50,9 +50,7 @@ pub async fn list_comments( let liked_only = data.liked_only; let disliked_only = data.disliked_only; - if liked_only.unwrap_or_default() && disliked_only.unwrap_or_default() { - return Err(LemmyError::from(LemmyErrorType::ContradictingFilters)); - } + check_conflicting_like_filters(liked_only, disliked_only)?; let page = data.page; let limit = data.limit; From ba779b978f06ee5a8c7f40562a1b41ebaded92f1 Mon Sep 17 00:00:00 2001 From: leoseg <70430884+leoseg@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:08:00 +0100 Subject: [PATCH 2/5] New parameter `read_only` for /api/v3/post/list (#5264) * added option to get only read only posts with unittests * formatted code * added index on (person_id, read) on post actions where read is not null * formatted sql * Update migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/up.sql Co-authored-by: dullbananas * Fixxed error in down.sql for migration of index on (person_id,read_only,post_id) on post_actions * Fixxed error in unittests * Update crates/db_views/src/post_view.rs Co-authored-by: dullbananas --------- Co-authored-by: dullbananas --- crates/api_common/src/post.rs | 2 ++ crates/apub/src/api/list_posts.rs | 2 ++ crates/db_views/src/post_view.rs | 35 +++++++++++++++++++ .../down.sql | 2 ++ .../up.sql | 4 +++ 5 files changed, 45 insertions(+) create mode 100644 migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/down.sql create mode 100644 migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/up.sql diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index db987d63c..543e39495 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -99,6 +99,8 @@ pub struct GetPosts { #[cfg_attr(feature = "full", ts(optional))] pub saved_only: Option, #[cfg_attr(feature = "full", ts(optional))] + pub read_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub liked_only: Option, #[cfg_attr(feature = "full", ts(optional))] pub disliked_only: Option, diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 63e737fdd..20e25f9a5 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -42,6 +42,7 @@ pub async fn list_posts( data.community_id }; let saved_only = data.saved_only; + let read_only = data.read_only; let show_hidden = data.show_hidden; let show_read = data.show_read; let show_nsfw = data.show_nsfw; @@ -78,6 +79,7 @@ pub async fn list_posts( sort, community_id, saved_only, + read_only, liked_only, disliked_only, page, diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 741df57ff..534b87e1e 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -317,6 +317,12 @@ fn queries<'a>() -> Queries< .filter(post_actions::saved.is_not_null()) .then_order_by(post_actions::saved.desc()); } + + if options.read_only.unwrap_or_default() { + query = query + .filter(post_actions::read.is_not_null()) + .then_order_by(post_actions::read.desc()) + } // Only hide the read posts, if the saved_only is false. Otherwise ppl with the hide_read // setting wont be able to see saved posts. else if !o.show_read.unwrap_or(o.local_user.show_read_posts()) { @@ -510,6 +516,7 @@ pub struct PostQuery<'a> { pub search_term: Option, pub url_only: Option, pub saved_only: Option, + pub read_only: Option, pub liked_only: Option, pub disliked_only: Option, pub title_only: Option, @@ -1236,6 +1243,34 @@ mod tests { Ok(()) } + #[test_context(Data)] + #[tokio::test] + #[serial] + async fn post_listing_read_only(data: &mut Data) -> LemmyResult<()> { + let pool = &data.pool(); + let pool = &mut pool.into(); + + // Only mark the bot post as read + // The read_only should only show the bot post + let post_read_form = + PostReadForm::new(data.inserted_bot_post.id, data.local_user_view.person.id); + PostRead::mark_as_read(pool, &post_read_form).await?; + + // Only read the post marked as read + let read_read_post_listing = PostQuery { + community_id: Some(data.inserted_community.id), + read_only: Some(true), + ..data.default_post_query() + } + .list(&data.site, pool) + .await?; + + // This should only include the bot post, not the one you created + assert_eq!(vec![POST_BY_BOT], names(&read_read_post_listing)); + + Ok(()) + } + #[test_context(Data)] #[tokio::test] #[serial] diff --git a/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/down.sql b/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/down.sql new file mode 100644 index 000000000..08750942c --- /dev/null +++ b/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/down.sql @@ -0,0 +1,2 @@ +DROP INDEX idx_post_actions_on_read_read_not_null; + diff --git a/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/up.sql b/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/up.sql new file mode 100644 index 000000000..03f9e4008 --- /dev/null +++ b/migrations/2024-12-15-151642_add_index_on_person_id_read_for_read_only_post_actions/up.sql @@ -0,0 +1,4 @@ +CREATE INDEX idx_post_actions_on_read_read_not_null ON post_actions (person_id, read, post_id) +WHERE + read IS NOT NULL; + From e9d27f28404da8a0a609f13979e43aae09caaaff Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 3 Jan 2025 05:16:25 -0500 Subject: [PATCH 3/5] Don't send out new user email verifies to admins, if already verified. (#5288) - Fixes #5272 --- crates/api/src/local_user/verify_email.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/api/src/local_user/verify_email.rs b/crates/api/src/local_user/verify_email.rs index 4b6a8c928..813b68364 100644 --- a/crates/api/src/local_user/verify_email.rs +++ b/crates/api/src/local_user/verify_email.rs @@ -19,6 +19,11 @@ pub async fn verify_email( let site_view = SiteView::read_local(&mut context.pool()).await?; let token = data.token.clone(); let verification = EmailVerification::read_for_token(&mut context.pool(), &token).await?; + let local_user_id = verification.local_user_id; + let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; + + // Check if their email has already been verified once, before this + let email_already_verified = local_user_view.local_user.email_verified; let form = LocalUserUpdateForm { // necessary in case this is a new signup @@ -27,18 +32,16 @@ pub async fn verify_email( email: Some(Some(verification.email)), ..Default::default() }; - let local_user_id = verification.local_user_id; LocalUser::update(&mut context.pool(), local_user_id, &form).await?; EmailVerification::delete_old_tokens_for_local_user(&mut context.pool(), local_user_id).await?; - // send out notification about registration application to admins if enabled - if site_view.local_site.application_email_admins { - let local_user = LocalUserView::read(&mut context.pool(), local_user_id).await?; - + // Send out notification about registration application to admins if enabled, and the user hasn't + // already been verified. + if site_view.local_site.application_email_admins && !email_already_verified { send_new_applicant_email_to_admins( - &local_user.person.name, + &local_user_view.person.name, &mut context.pool(), context.settings(), ) From 6de73f37ca79c99e6985656ba6c011006fa6da91 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Fri, 3 Jan 2025 15:57:02 +0100 Subject: [PATCH 4/5] Rename variable --- crates/db_views/src/post_view.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 534b87e1e..2c32fd918 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -318,7 +318,7 @@ fn queries<'a>() -> Queries< .then_order_by(post_actions::saved.desc()); } - if options.read_only.unwrap_or_default() { + if o.read_only.unwrap_or_default() { query = query .filter(post_actions::read.is_not_null()) .then_order_by(post_actions::read.desc()) From 41421991d69c146762cab6260d3480b597f0450a Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 3 Jan 2025 19:09:24 +0000 Subject: [PATCH 5/5] Error handling for thumbnail generation (ref #5196) (#5298) --- crates/api_common/src/request.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index 02e889872..4ccd032b9 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -32,7 +32,7 @@ use reqwest::{ }; use reqwest_middleware::ClientWithMiddleware; use serde::{Deserialize, Serialize}; -use tracing::info; +use tracing::{info, warn}; use url::Url; use urlencoding::encode; use webpage::HTML; @@ -173,15 +173,23 @@ pub async fn generate_post_link_metadata( metadata.opengraph_data.image.clone() }; + // Attempt to generate a thumbnail depending on the instance settings. Either by proxying, + // storing image persistently in pict-rs or returning the remote url directly as thumbnail. let thumbnail_url = if let (false, Some(url)) = (is_image_post, custom_thumbnail) { - proxy_image_link(url, &context).await.ok() - } else if let (true, Some(url)) = (allow_generate_thumbnail, image_url) { + proxy_image_link(url.clone(), &context) + .await + .map_err(|e| warn!("Failed to proxy thumbnail: {e}")) + .ok() + .or(Some(url.into())) + } else if let (true, Some(url)) = (allow_generate_thumbnail, image_url.clone()) { generate_pictrs_thumbnail(&url, &context) .await + .map_err(|e| warn!("Failed to generate thumbnail: {e}")) .ok() .map(Into::into) + .or(image_url) } else { - metadata.opengraph_data.image.clone() + image_url.clone() }; let form = PostUpdateForm {