diff --git a/Cargo.lock b/Cargo.lock index 3ba344888..17a006fda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -977,9 +977,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" dependencies = [ "clap_builder", "clap_derive", @@ -987,9 +987,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" dependencies = [ "anstream", "anstyle", @@ -999,9 +999,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3286,7 +3286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -5210,9 +5210,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "indexmap 2.2.6", "itoa", diff --git a/crates/api/src/comment/distinguish.rs b/crates/api/src/comment/distinguish.rs index dfd850e89..0683af9a4 100644 --- a/crates/api/src/comment/distinguish.rs +++ b/crates/api/src/comment/distinguish.rs @@ -17,9 +17,13 @@ pub async fn distinguish_comment( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let orig_comment = CommentView::read( + &mut context.pool(), + data.comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, @@ -54,7 +58,7 @@ pub async fn distinguish_comment( let comment_view = CommentView::read( &mut context.pool(), data.comment_id, - Some(local_user_view.person.id), + Some(&local_user_view.local_user), ) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index d0aa4a6c2..b8a1c6f76 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -35,9 +35,13 @@ pub async fn like_comment( check_bot_account(&local_user_view.person)?; let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let orig_comment = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, diff --git a/crates/api/src/comment/list_comment_likes.rs b/crates/api/src/comment/list_comment_likes.rs index 8c2c9dd32..4b2e1c8b3 100644 --- a/crates/api/src/comment/list_comment_likes.rs +++ b/crates/api/src/comment/list_comment_likes.rs @@ -17,7 +17,7 @@ pub async fn list_comment_likes( let comment_view = CommentView::read( &mut context.pool(), data.comment_id, - Some(local_user_view.person.id), + Some(&local_user_view.local_user), ) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; diff --git a/crates/api/src/comment/save.rs b/crates/api/src/comment/save.rs index f9d649e48..67c2db331 100644 --- a/crates/api/src/comment/save.rs +++ b/crates/api/src/comment/save.rs @@ -32,10 +32,13 @@ pub async fn save_comment( } let comment_id = data.comment_id; - let person_id = local_user_view.person.id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let comment_view = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(Json(CommentResponse { comment_view, diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs index c008d1df2..a269df07f 100644 --- a/crates/api/src/comment_report/create.rs +++ b/crates/api/src/comment_report/create.rs @@ -35,9 +35,13 @@ pub async fn create_comment_report( let person_id = local_user_view.person.id; let comment_id = data.comment_id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let comment_view = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, diff --git a/crates/api/src/community/block.rs b/crates/api/src/community/block.rs index 449addf32..ad31548ea 100644 --- a/crates/api/src/community/block.rs +++ b/crates/api/src/community/block.rs @@ -50,10 +50,14 @@ pub async fn block_community( .with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?; } - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) - .await? - .ok_or(LemmyErrorType::CouldntFindCommunity)?; + let community_view = CommunityView::read( + &mut context.pool(), + community_id, + Some(&local_user_view.local_user), + false, + ) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; ActivityChannel::submit_activity( SendActivityData::FollowCommunity( diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index 853cfde14..2236fa5bc 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -62,11 +62,14 @@ pub async fn follow_community( } let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) - .await? - .ok_or(LemmyErrorType::CouldntFindCommunity)?; + let community_view = CommunityView::read( + &mut context.pool(), + community_id, + Some(&local_user_view.local_user), + false, + ) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; diff --git a/crates/api/src/community/transfer.rs b/crates/api/src/community/transfer.rs index 5f3a6032e..a32c069b1 100644 --- a/crates/api/src/community/transfer.rs +++ b/crates/api/src/community/transfer.rs @@ -76,11 +76,14 @@ pub async fn transfer_community( ModTransferCommunity::create(&mut context.pool(), &form).await?; let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) - .await? - .ok_or(LemmyErrorType::CouldntFindCommunity)?; + let community_view = CommunityView::read( + &mut context.pool(), + community_id, + Some(&local_user_view.local_user), + false, + ) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let community_id = data.community_id; let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id) diff --git a/crates/api/src/post/feature.rs b/crates/api/src/post/feature.rs index 40cbf6794..ec99a3345 100644 --- a/crates/api/src/post/feature.rs +++ b/crates/api/src/post/feature.rs @@ -72,11 +72,5 @@ pub async fn feature_post( ) .await?; - build_post_response( - &context, - orig_post.community_id, - &local_user_view.person, - post_id, - ) - .await + build_post_response(&context, orig_post.community_id, local_user_view, post_id).await } diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index fccd9f8df..e6903fb3c 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -85,11 +85,5 @@ pub async fn like_post( ) .await?; - build_post_response( - context.deref(), - post.community_id, - &local_user_view.person, - post_id, - ) - .await + build_post_response(context.deref(), post.community_id, local_user_view, post_id).await } diff --git a/crates/api/src/post/lock.rs b/crates/api/src/post/lock.rs index 05db8ebbb..36f9c2a33 100644 --- a/crates/api/src/post/lock.rs +++ b/crates/api/src/post/lock.rs @@ -63,11 +63,5 @@ pub async fn lock_post( ) .await?; - build_post_response( - &context, - orig_post.community_id, - &local_user_view.person, - post_id, - ) - .await + build_post_response(&context, orig_post.community_id, local_user_view, post_id).await } diff --git a/crates/api/src/post/save.rs b/crates/api/src/post/save.rs index 96dd85579..85dfc11e3 100644 --- a/crates/api/src/post/save.rs +++ b/crates/api/src/post/save.rs @@ -34,9 +34,14 @@ pub async fn save_post( let post_id = data.post_id; let person_id = local_user_view.person.id; - let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false) - .await? - .ok_or(LemmyErrorType::CouldntFindPost)?; + let post_view = PostView::read( + &mut context.pool(), + post_id, + Some(&local_user_view.local_user), + false, + ) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; mark_post_as_read(person_id, post_id, &mut context.pool()).await?; diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs index 70d95e160..f99dfc689 100644 --- a/crates/api/src/site/purge/comment.rs +++ b/crates/api/src/site/purge/comment.rs @@ -29,9 +29,13 @@ pub async fn purge_comment( let comment_id = data.comment_id; // Read the comment to get the post_id and community - let comment_view = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let comment_view = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; let post_id = comment_view.comment.post_id; diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index 85cf065eb..200284b00 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -36,8 +36,8 @@ pub async fn build_comment_response( local_user_view: Option, recipient_ids: Vec, ) -> LemmyResult { - let person_id = local_user_view.map(|l| l.person.id); - let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id) + let local_user = local_user_view.map(|l| l.local_user); + let comment_view = CommentView::read(&mut context.pool(), comment_id, local_user.as_ref()) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(CommentResponse { @@ -54,11 +54,11 @@ pub async fn build_community_response( let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &local_user_view.person, community_id) .await .is_ok(); - let person_id = local_user_view.person.id; + let local_user = local_user_view.local_user; let community_view = CommunityView::read( &mut context.pool(), community_id, - Some(person_id), + Some(&local_user), is_mod_or_admin, ) .await? @@ -74,16 +74,17 @@ pub async fn build_community_response( pub async fn build_post_response( context: &LemmyContext, community_id: CommunityId, - person: &Person, + local_user_view: LocalUserView, post_id: PostId, ) -> LemmyResult> { - let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), person, community_id) + let local_user = local_user_view.local_user; + let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &local_user_view.person, community_id) .await .is_ok(); let post_view = PostView::read( &mut context.pool(), post_id, - Some(person.id), + Some(&local_user), is_mod_or_admin, ) .await? @@ -103,6 +104,7 @@ pub async fn send_local_notifs( let mut recipient_ids = Vec::new(); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); + // let person = my_local_user.person; // Read the comment view to get extra info let comment_view = CommentView::read(&mut context.pool(), comment_id, None) .await? diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 636f83392..b7c65740c 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -8,20 +8,18 @@ use lemmy_api_common::{ utils::{ check_community_user_action, check_post_deleted_or_removed, - generate_local_apub_endpoint, get_url_blocklist, is_mod_or_admin, local_site_to_slur_regex, process_markdown, update_read_comments, - EndpointType, }, }; use lemmy_db_schema::{ impls::actor_language::default_post_language, source::{ actor_language::CommunityLanguage, - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm, CommentUpdateForm}, + comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, comment_reply::{CommentReply, CommentReplyUpdateForm}, local_site::LocalSite, person_mention::{PersonMention, PersonMentionUpdateForm}, @@ -56,7 +54,7 @@ pub async fn create_comment( let post_view = PostView::read( &mut context.pool(), post_id, - Some(local_user_view.person.id), + Some(&local_user_view.local_user), true, ) .await? @@ -126,25 +124,7 @@ pub async fn create_comment( .await .with_lemmy_type(LemmyErrorType::CouldntCreateComment)?; - // Necessary to update the ap_id let inserted_comment_id = inserted_comment.id; - let protocol_and_hostname = context.settings().get_protocol_and_hostname(); - - let apub_id = generate_local_apub_endpoint( - EndpointType::Comment, - &inserted_comment_id.to_string(), - &protocol_and_hostname, - )?; - let updated_comment = Comment::update( - &mut context.pool(), - inserted_comment_id, - &CommentUpdateForm { - ap_id: Some(apub_id), - ..Default::default() - }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreateComment)?; // Scan the comment for user mentions, add those rows let mentions = scrape_text_for_mentions(&content); @@ -170,7 +150,7 @@ pub async fn create_comment( .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; ActivityChannel::submit_activity( - SendActivityData::CreateComment(updated_comment.clone()), + SendActivityData::CreateComment(inserted_comment.clone()), &context, ) .await?; diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 2b1a20f89..29706d365 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -21,9 +21,13 @@ pub async fn delete_comment( local_user_view: LocalUserView, ) -> LemmyResult> { let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let orig_comment = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; // Dont delete it if its already been deleted. if orig_comment.comment.deleted == data.deleted { diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index 926472b94..83ef82e3a 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -25,9 +25,13 @@ pub async fn remove_comment( local_user_view: LocalUserView, ) -> LemmyResult> { let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let orig_comment = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_mod_action( &local_user_view.person, @@ -68,14 +72,8 @@ pub async fn remove_comment( }; ModRemoveComment::create(&mut context.pool(), &form).await?; - let recipient_ids = send_local_notifs( - vec![], - comment_id, - &local_user_view.person.clone(), - false, - &context, - ) - .await?; + let recipient_ids = + send_local_notifs(vec![], comment_id, &local_user_view.person, false, &context).await?; let updated_comment_id = updated_comment.id; ActivityChannel::submit_activity( diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 4c8cf9436..32bd08240 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -36,9 +36,13 @@ pub async fn update_comment( let local_site = LocalSite::read(&mut context.pool()).await?; let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let orig_comment = CommentView::read( + &mut context.pool(), + comment_id, + Some(&local_user_view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 0b0fad5dc..0f6abc2aa 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -8,13 +8,11 @@ use lemmy_api_common::{ send_activity::SendActivityData, utils::{ check_community_user_action, - generate_local_apub_endpoint, get_url_blocklist, honeypot_check, local_site_to_slur_regex, mark_post_as_read, process_markdown_opt, - EndpointType, }, }; use lemmy_db_schema::{ @@ -23,7 +21,7 @@ use lemmy_db_schema::{ actor_language::CommunityLanguage, community::Community, local_site::LocalSite, - post::{Post, PostInsertForm, PostLike, PostLikeForm, PostUpdateForm}, + post::{Post, PostInsertForm, PostLike, PostLikeForm}, }, traits::{Crud, Likeable}, utils::diesel_url_create, @@ -147,26 +145,8 @@ pub async fn create_post( .await .with_lemmy_type(LemmyErrorType::CouldntCreatePost)?; - let inserted_post_id = inserted_post.id; - let protocol_and_hostname = context.settings().get_protocol_and_hostname(); - let apub_id = generate_local_apub_endpoint( - EndpointType::Post, - &inserted_post_id.to_string(), - &protocol_and_hostname, - )?; - let updated_post = Post::update( - &mut context.pool(), - inserted_post_id, - &PostUpdateForm { - ap_id: Some(apub_id), - ..Default::default() - }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreatePost)?; - generate_post_link_metadata( - updated_post.clone(), + inserted_post.clone(), custom_thumbnail.map(Into::into), |post| Some(SendActivityData::CreatePost(post)), Some(local_site), @@ -189,11 +169,11 @@ pub async fn create_post( mark_post_as_read(person_id, post_id, &mut context.pool()).await?; - if let Some(url) = updated_post.url.clone() { + if let Some(url) = inserted_post.url.clone() { if community.visibility == CommunityVisibility::Public { spawn_try_task(async move { let mut webmention = - Webmention::new::(updated_post.ap_id.clone().into(), url.clone().into())?; + Webmention::new::(inserted_post.ap_id.clone().into(), url.clone().into())?; webmention.set_checked(true); match webmention .send() @@ -208,5 +188,5 @@ pub async fn create_post( } }; - build_post_response(&context, community_id, &local_user_view.person, post_id).await + build_post_response(&context, community_id, local_user_view, post_id).await } diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index 696566c8e..6834030ac 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -62,7 +62,7 @@ pub async fn delete_post( build_post_response( &context, orig_post.community_id, - &local_user_view.person, + local_user_view, data.post_id, ) .await diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 60b5609a9..ebf8940a2 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -55,9 +55,15 @@ pub async fn get_post( .await .is_ok(); - let post_view = PostView::read(&mut context.pool(), post_id, person_id, is_mod_or_admin) - .await? - .ok_or(LemmyErrorType::CouldntFindPost)?; + let local_user = local_user_view.map(|l| l.local_user); + let post_view = PostView::read( + &mut context.pool(), + post_id, + local_user.as_ref(), + is_mod_or_admin, + ) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let post_id = post_view.post.id; if let Some(person_id) = person_id { @@ -76,20 +82,19 @@ pub async fn get_post( let community_view = CommunityView::read( &mut context.pool(), community_id, - person_id, + local_user.as_ref(), is_mod_or_admin, ) .await? .ok_or(LemmyErrorType::CouldntFindCommunity)?; let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - let local_user = local_user_view.as_ref().map(|u| &u.local_user); // Fetch the cross_posts let cross_posts = if let Some(url) = &post_view.post.url { let mut x_posts = PostQuery { url_search: Some(url.inner().as_str().into()), - local_user, + local_user: local_user.as_ref(), ..Default::default() } .list(&local_site.site, &mut context.pool()) diff --git a/crates/api_crud/src/post/remove.rs b/crates/api_crud/src/post/remove.rs index 682ed75d3..4ca15c90f 100644 --- a/crates/api_crud/src/post/remove.rs +++ b/crates/api_crud/src/post/remove.rs @@ -73,11 +73,5 @@ pub async fn remove_post( ) .await?; - build_post_response( - &context, - orig_post.community_id, - &local_user_view.person, - post_id, - ) - .await + build_post_response(&context, orig_post.community_id, local_user_view, post_id).await } diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 9e665aed6..cd4b2d41b 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -137,7 +137,7 @@ pub async fn update_post( build_post_response( context.deref(), orig_post.community_id, - &local_user_view.person, + local_user_view, post_id, ) .await diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 0381d196c..46908da6e 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -6,19 +6,17 @@ use lemmy_api_common::{ send_activity::{ActivityChannel, SendActivityData}, utils::{ check_person_block, - generate_local_apub_endpoint, get_interface_language, get_url_blocklist, local_site_to_slur_regex, process_markdown, send_email_to_user, - EndpointType, }, }; use lemmy_db_schema::{ source::{ local_site::LocalSite, - private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm}, + private_message::{PrivateMessage, PrivateMessageInsertForm}, }, traits::Crud, }; @@ -58,24 +56,6 @@ pub async fn create_private_message( .await .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - let inserted_private_message_id = inserted_private_message.id; - let protocol_and_hostname = context.settings().get_protocol_and_hostname(); - let apub_id = generate_local_apub_endpoint( - EndpointType::PrivateMessage, - &inserted_private_message_id.to_string(), - &protocol_and_hostname, - )?; - PrivateMessage::update( - &mut context.pool(), - inserted_private_message.id, - &PrivateMessageUpdateForm { - ap_id: Some(apub_id), - ..Default::default() - }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id) .await? .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index dae7719ae..62fd6ec0b 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -29,7 +29,7 @@ pub async fn get_community( check_private_instance(&local_user_view, &local_site)?; - let person_id = local_user_view.as_ref().map(|u| u.person.id); + let local_user = local_user_view.as_ref().map(|u| &u.local_user); let community_id = match data.id { Some(id) => id, @@ -53,7 +53,7 @@ pub async fn get_community( let community_view = CommunityView::read( &mut context.pool(), community_id, - person_id, + local_user, is_mod_or_admin, ) .await? diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index 47f6c5d06..3f2591241 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -10,7 +10,7 @@ use lemmy_api_common::{ site::{ResolveObject, ResolveObjectResponse}, utils::check_private_instance, }; -use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool}; +use lemmy_db_schema::{source::local_site::LocalSite, utils::DbPool}; use lemmy_db_views::structs::{CommentView, LocalUserView, PostView}; use lemmy_db_views_actor::structs::{CommunityView, PersonView}; use lemmy_utils::error::{LemmyErrorExt2, LemmyErrorType, LemmyResult}; @@ -23,10 +23,9 @@ pub async fn resolve_object( ) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; - let person_id = local_user_view.map(|v| v.person.id); // If we get a valid personId back we can safely assume that the user is authenticated, // if there's no personId then the JWT was missing or invalid. - let is_authenticated = person_id.is_some(); + let is_authenticated = local_user_view.is_some(); let res = if is_authenticated { // user is fully authenticated; allow remote lookups as well. @@ -37,24 +36,26 @@ pub async fn resolve_object( } .with_lemmy_type(LemmyErrorType::CouldntFindObject)?; - convert_response(res, person_id, &mut context.pool()) + convert_response(res, local_user_view, &mut context.pool()) .await .with_lemmy_type(LemmyErrorType::CouldntFindObject) } async fn convert_response( object: SearchableObjects, - user_id: Option, + local_user_view: Option, pool: &mut DbPool<'_>, ) -> LemmyResult> { use SearchableObjects::*; let removed_or_deleted; let mut res = ResolveObjectResponse::default(); + let local_user = local_user_view.map(|l| l.local_user); + match object { Post(p) => { removed_or_deleted = p.deleted || p.removed; res.post = Some( - PostView::read(pool, p.id, user_id, false) + PostView::read(pool, p.id, local_user.as_ref(), false) .await? .ok_or(LemmyErrorType::CouldntFindPost)?, ) @@ -62,7 +63,7 @@ async fn convert_response( Comment(c) => { removed_or_deleted = c.deleted || c.removed; res.comment = Some( - CommentView::read(pool, c.id, user_id) + CommentView::read(pool, c.id, local_user.as_ref()) .await? .ok_or(LemmyErrorType::CouldntFindComment)?, ) @@ -79,7 +80,7 @@ async fn convert_response( UserOrCommunity::Community(c) => { removed_or_deleted = c.deleted || c.removed; res.community = Some( - CommunityView::read(pool, c.id, user_id, false) + CommunityView::read(pool, c.id, local_user.as_ref(), false) .await? .ok_or(LemmyErrorType::CouldntFindCommunity)?, ) diff --git a/crates/db_schema/replaceable_schema/triggers.sql b/crates/db_schema/replaceable_schema/triggers.sql index 87866e89c..973d3325f 100644 --- a/crates/db_schema/replaceable_schema/triggers.sql +++ b/crates/db_schema/replaceable_schema/triggers.sql @@ -564,6 +564,10 @@ BEGIN IF NOT (NEW.path ~ ('*.' || id)::lquery) THEN NEW.path = NEW.path || id; END IF; + -- Set local ap_id + IF NEW.local THEN + NEW.ap_id = coalesce(NEW.ap_id, r.local_url ('/comment/' || id)); + END IF; RETURN NEW; END $$; @@ -573,3 +577,39 @@ CREATE TRIGGER change_values FOR EACH ROW EXECUTE FUNCTION r.comment_change_values (); +CREATE FUNCTION r.post_change_values () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- Set local ap_id + IF NEW.local THEN + NEW.ap_id = coalesce(NEW.ap_id, r.local_url ('/post/' || NEW.id::text)); + END IF; + RETURN NEW; +END +$$; + +CREATE TRIGGER change_values + BEFORE INSERT ON post + FOR EACH ROW + EXECUTE FUNCTION r.post_change_values (); + +CREATE FUNCTION r.private_message_change_values () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $$ +BEGIN + -- Set local ap_id + IF NEW.local THEN + NEW.ap_id = coalesce(NEW.ap_id, r.local_url ('/private_message/' || NEW.id::text)); + END IF; + RETURN NEW; +END +$$; + +CREATE TRIGGER change_values + BEFORE INSERT ON private_message + FOR EACH ROW + EXECUTE FUNCTION r.private_message_change_values (); + diff --git a/crates/db_schema/replaceable_schema/utils.sql b/crates/db_schema/replaceable_schema/utils.sql index f236c5387..c766d25f2 100644 --- a/crates/db_schema/replaceable_schema/utils.sql +++ b/crates/db_schema/replaceable_schema/utils.sql @@ -8,7 +8,7 @@ CREATE FUNCTION r.controversy_rank (upvotes numeric, downvotes numeric) 0 ELSE ( - upvotes + downvotes) * CASE WHEN upvotes > downvotes THEN + upvotes + downvotes) ^ CASE WHEN upvotes > downvotes THEN downvotes::float / upvotes::float ELSE upvotes::float / downvotes::float @@ -57,6 +57,13 @@ BEGIN END; $$; +CREATE FUNCTION r.local_url (url_path text) + RETURNS text + LANGUAGE sql + STABLE PARALLEL SAFE RETURN ( +current_setting('lemmy.protocol_and_hostname') || url_path +); + -- This function creates statement-level triggers for all operation types. It's designed this way -- because of these limitations: -- * A trigger that uses transition tables can only handle 1 operation type. diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index 0ffd53f86..aa7b418fe 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -223,6 +223,7 @@ mod tests { use diesel_ltree::Ltree; use pretty_assertions::assert_eq; use serial_test::serial; + use url::Url; #[tokio::test] #[serial] @@ -273,7 +274,12 @@ mod tests { path: Ltree(format!("0.{}", inserted_comment.id)), published: inserted_comment.published, updated: None, - ap_id: inserted_comment.ap_id.clone(), + ap_id: Url::parse(&format!( + "https://lemmy-alpha/comment/{}", + inserted_comment.id + )) + .unwrap() + .into(), distinguished: false, local: true, language_id: LanguageId::default(), diff --git a/crates/db_schema/src/impls/local_user.rs b/crates/db_schema/src/impls/local_user.rs index 9b59e07ba..694979ade 100644 --- a/crates/db_schema/src/impls/local_user.rs +++ b/crates/db_schema/src/impls/local_user.rs @@ -1,6 +1,6 @@ use crate::{ newtypes::{DbUrl, LanguageId, LocalUserId, PersonId}, - schema::{local_user, person, registration_application}, + schema::{community, local_user, person, registration_application}, source::{ actor_language::LocalUserLanguage, local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm}, @@ -13,6 +13,7 @@ use crate::{ now, DbPool, }, + CommunityVisibility, }; use bcrypt::{hash, DEFAULT_COST}; use diesel::{ @@ -225,6 +226,12 @@ pub trait LocalUserOptionHelper { fn show_read_posts(&self) -> bool; fn is_admin(&self) -> bool; fn show_nsfw(&self, site: &Site) -> bool; + fn visible_communities_only(&self, query: Q) -> Q + where + Q: diesel::query_dsl::methods::FilterDsl< + diesel::dsl::Eq, + Output = Q, + >; } impl LocalUserOptionHelper for Option<&LocalUser> { @@ -253,6 +260,20 @@ impl LocalUserOptionHelper for Option<&LocalUser> { .map(|l| l.show_nsfw) .unwrap_or(site.content_warning.is_some()) } + + fn visible_communities_only(&self, query: Q) -> Q + where + Q: diesel::query_dsl::methods::FilterDsl< + diesel::dsl::Eq, + Output = Q, + >, + { + if self.is_none() { + query.filter(community::visibility.eq(CommunityVisibility::Public)) + } else { + query + } + } } impl LocalUserInsertForm { diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index ac6cf76aa..8e14bee9f 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -390,6 +390,7 @@ mod tests { use pretty_assertions::assert_eq; use serial_test::serial; use std::collections::HashSet; + use url::Url; #[tokio::test] #[serial] @@ -447,7 +448,9 @@ mod tests { embed_description: None, embed_video_url: None, thumbnail_url: None, - ap_id: inserted_post.ap_id.clone(), + ap_id: Url::parse(&format!("https://lemmy-alpha/post/{}", inserted_post.id)) + .unwrap() + .into(), local: true, language_id: Default::default(), featured_community: false, diff --git a/crates/db_schema/src/impls/private_message.rs b/crates/db_schema/src/impls/private_message.rs index 3cbfd052d..fe3629a1a 100644 --- a/crates/db_schema/src/impls/private_message.rs +++ b/crates/db_schema/src/impls/private_message.rs @@ -100,6 +100,7 @@ mod tests { }; use pretty_assertions::assert_eq; use serial_test::serial; + use url::Url; #[tokio::test] #[serial] @@ -138,7 +139,12 @@ mod tests { read: false, updated: None, published: inserted_private_message.published, - ap_id: inserted_private_message.ap_id.clone(), + ap_id: Url::parse(&format!( + "https://lemmy-alpha/private_message/{}", + inserted_private_message.id + )) + .unwrap() + .into(), local: true, }; diff --git a/crates/db_schema/src/newtypes.rs b/crates/db_schema/src/newtypes.rs index 10abfaec4..c5c9e8e84 100644 --- a/crates/db_schema/src/newtypes.rs +++ b/crates/db_schema/src/newtypes.rs @@ -85,12 +85,6 @@ impl fmt::Display for PrivateMessageId { /// The person mention id. pub struct PersonMentionId(i32); -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)] -#[cfg_attr(feature = "full", derive(DieselNewType, TS))] -#[cfg_attr(feature = "full", ts(export))] -/// The person block id. -pub struct PersonBlockId(i32); - #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "full", derive(DieselNewType, TS))] #[cfg_attr(feature = "full", ts(export))] diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index 6761adeee..ec9f9ded7 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -1,15 +1,7 @@ -use crate::{ - diesel::ExpressionMethods, - newtypes::{DbUrl, PersonId}, - schema::community, - CommentSortType, - CommunityVisibility, - SortType, -}; +use crate::{newtypes::DbUrl, CommentSortType, SortType}; use chrono::{DateTime, TimeDelta, Utc}; use deadpool::Runtime; use diesel::{ - dsl, helper_types::AsExprOf, pg::Pg, query_builder::{Query, QueryFragment}, @@ -30,7 +22,8 @@ use diesel_async::{ AsyncDieselConnectionManager, ManagerConfig, }, - SimpleAsyncConnection, + AsyncConnection, + RunQueryDsl, }; use futures_util::{future::BoxFuture, Future, FutureExt}; use i_love_jesus::CursorKey; @@ -332,34 +325,50 @@ pub fn diesel_url_create(opt: Option<&str>) -> LemmyResult> { fn establish_connection(config: &str) -> BoxFuture> { let fut = async { - rustls::crypto::ring::default_provider() - .install_default() - .expect("Failed to install rustls crypto provider"); + // We only support TLS with sslmode=require currently + let mut conn = if config.contains("sslmode=require") { + rustls::crypto::ring::default_provider() + .install_default() + .expect("Failed to install rustls crypto provider"); - let rustls_config = DangerousClientConfigBuilder { - cfg: ClientConfig::builder(), - } - .with_custom_certificate_verifier(Arc::new(NoCertVerifier {})) - .with_no_client_auth(); - - let tls = tokio_postgres_rustls::MakeRustlsConnect::new(rustls_config); - let (client, conn) = tokio_postgres::connect(config, tls) - .await - .map_err(|e| ConnectionError::BadConnection(e.to_string()))?; - tokio::spawn(async move { - if let Err(e) = conn.await { - error!("Database connection failed: {e}"); + let rustls_config = DangerousClientConfigBuilder { + cfg: ClientConfig::builder(), } - }); - let mut conn = AsyncPgConnection::try_from(client).await?; - // * Change geqo_threshold back to default value if it was changed, so it's higher than the - // collapse limits - // * Change collapse limits from 8 to 11 so the query planner can find a better table join order - // for more complicated queries - conn - .batch_execute("SET geqo_threshold=12;SET from_collapse_limit=11;SET join_collapse_limit=11;") - .await - .map_err(ConnectionError::CouldntSetupConfiguration)?; + .with_custom_certificate_verifier(Arc::new(NoCertVerifier {})) + .with_no_client_auth(); + + let tls = tokio_postgres_rustls::MakeRustlsConnect::new(rustls_config); + let (client, conn) = tokio_postgres::connect(config, tls) + .await + .map_err(|e| ConnectionError::BadConnection(e.to_string()))?; + tokio::spawn(async move { + if let Err(e) = conn.await { + error!("Database connection failed: {e}"); + } + }); + AsyncPgConnection::try_from(client).await? + } else { + AsyncPgConnection::establish(config).await? + }; + + diesel::select(( + // Change geqo_threshold back to default value if it was changed, so it's higher than the + // collapse limits + functions::set_config("geqo_threshold", "12", false), + // Change collapse limits from 8 to 11 so the query planner can find a better table join + // order for more complicated queries + functions::set_config("from_collapse_limit", "11", false), + functions::set_config("join_collapse_limit", "11", false), + // Set `lemmy.protocol_and_hostname` so triggers can use it + functions::set_config( + "lemmy.protocol_and_hostname", + SETTINGS.get_protocol_and_hostname(), + false, + ), + )) + .execute(&mut conn) + .await + .map_err(ConnectionError::CouldntSetupConfiguration)?; Ok(conn) }; fut.boxed() @@ -418,17 +427,11 @@ impl ServerCertVerifier for NoCertVerifier { pub async fn build_db_pool() -> LemmyResult { let db_url = SETTINGS.get_database_url(); - // We only support TLS with sslmode=require currently - let tls_enabled = db_url.contains("sslmode=require"); - let manager = if tls_enabled { - // diesel-async does not support any TLS connections out of the box, so we need to manually - // provide a setup function which handles creating the connection - let mut config = ManagerConfig::default(); - config.custom_setup = Box::new(establish_connection); - AsyncDieselConnectionManager::::new_with_config(&db_url, config) - } else { - AsyncDieselConnectionManager::::new(&db_url) - }; + // diesel-async does not support any TLS connections out of the box, so we need to manually + // provide a setup function which handles creating the connection + let mut config = ManagerConfig::default(); + config.custom_setup = Box::new(establish_connection); + let manager = AsyncDieselConnectionManager::::new_with_config(&db_url, config); let pool = Pool::builder(manager) .max_size(SETTINGS.database.pool_size) .runtime(Runtime::Tokio1) @@ -485,7 +488,7 @@ static EMAIL_REGEX: Lazy = Lazy::new(|| { }); pub mod functions { - use diesel::sql_types::{BigInt, Text, Timestamptz}; + use diesel::sql_types::{BigInt, Bool, Text, Timestamptz}; sql_function! { #[sql_name = "r.hot_rank"] @@ -508,6 +511,8 @@ pub mod functions { // really this function is variadic, this just adds the two-argument version sql_function!(fn coalesce(x: diesel::sql_types::Nullable, y: T) -> T); + + sql_function!(fn set_config(setting_name: Text, new_value: Text, is_local: Bool) -> Text); } pub const DELETED_REPLACEMENT_TEXT: &str = "*Permanently Deleted*"; @@ -579,20 +584,6 @@ impl Queries { } } -pub fn visible_communities_only(my_person_id: Option, query: Q) -> Q -where - Q: diesel::query_dsl::methods::FilterDsl< - dsl::Eq, - Output = Q, - >, -{ - if my_person_id.is_none() { - query.filter(community::visibility.eq(CommunityVisibility::Public)) - } else { - query - } -} - #[cfg(test)] #[allow(clippy::indexing_slicing)] mod tests { diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index cd7560a00..0e476b3b6 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -36,22 +36,13 @@ use lemmy_db_schema::{ post, }, source::local_user::LocalUser, - utils::{ - fuzzy_search, - limit_and_offset, - visible_communities_only, - DbConn, - DbPool, - ListFn, - Queries, - ReadFn, - }, + utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, CommentSortType, ListingType, }; fn queries<'a>() -> Queries< - impl ReadFn<'a, CommentView, (CommentId, Option)>, + impl ReadFn<'a, CommentView, (CommentId, Option<&'a LocalUser>)>, impl ListFn<'a, CommentView, CommentQuery<'a>>, > { let is_creator_banned_from_community = exists( @@ -182,9 +173,12 @@ fn queries<'a>() -> Queries< }; let read = move |mut conn: DbConn<'a>, - (comment_id, my_person_id): (CommentId, Option)| async move { - let mut query = all_joins(comment::table.find(comment_id).into_boxed(), my_person_id); - query = visible_communities_only(my_person_id, query); + (comment_id, my_local_user): (CommentId, Option<&'a LocalUser>)| async move { + let mut query = all_joins( + comment::table.find(comment_id).into_boxed(), + my_local_user.person_id(), + ); + query = my_local_user.visible_communities_only(query); query.first(&mut conn).await }; @@ -301,7 +295,7 @@ fn queries<'a>() -> Queries< query = query.filter(not(is_creator_blocked(person_id_join))); }; - query = visible_communities_only(options.local_user.person_id(), query); + query = options.local_user.visible_communities_only(query); // A Max depth given means its a tree fetch let (limit, offset) = if let Some(max_depth) = options.max_depth { @@ -366,16 +360,16 @@ fn queries<'a>() -> Queries< } impl CommentView { - pub async fn read( + pub async fn read<'a>( pool: &mut DbPool<'_>, comment_id: CommentId, - my_person_id: Option, + my_local_user: Option<&'a LocalUser>, ) -> Result, Error> { // If a person is given, then my_vote (res.9), if None, should be 0, not null // Necessary to differentiate between other person's votes - if let Ok(Some(res)) = queries().read(pool, (comment_id, my_person_id)).await { + if let Ok(Some(res)) = queries().read(pool, (comment_id, my_local_user)).await { let mut new_view = res.clone(); - if my_person_id.is_some() && res.my_vote.is_none() { + if my_local_user.is_some() && res.my_vote.is_none() { new_view.my_vote = Some(0); } if res.comment.deleted || res.comment.removed { @@ -676,7 +670,7 @@ mod tests { let read_comment_from_blocked_person = CommentView::read( pool, data.inserted_comment_1.id, - Some(data.timmy_local_user_view.person.id), + Some(&data.timmy_local_user_view.local_user), ) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; @@ -1171,7 +1165,7 @@ mod tests { let authenticated_comment = CommentView::read( pool, data.inserted_comment_0.id, - Some(data.timmy_local_user_view.person.id), + Some(&data.timmy_local_user_view.local_user), ) .await; assert!(authenticated_comment.is_ok()); @@ -1211,7 +1205,7 @@ mod tests { let comment_view = CommentView::read( pool, data.inserted_comment_0.id, - Some(inserted_banned_from_comm_local_user.person_id), + Some(&inserted_banned_from_comm_local_user), ) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; @@ -1232,7 +1226,7 @@ mod tests { let comment_view = CommentView::read( pool, data.inserted_comment_0.id, - Some(data.timmy_local_user_view.person.id), + Some(&data.timmy_local_user_view.local_user), ) .await? .ok_or(LemmyErrorType::CouldntFindComment)?; diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 0e22f689b..588bb017b 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -49,7 +49,6 @@ use lemmy_db_schema::{ get_conn, limit_and_offset, now, - visible_communities_only, Commented, DbConn, DbPool, @@ -64,7 +63,7 @@ use lemmy_db_schema::{ use tracing::debug; fn queries<'a>() -> Queries< - impl ReadFn<'a, PostView, (PostId, Option, bool)>, + impl ReadFn<'a, PostView, (PostId, Option<&'a LocalUser>, bool)>, impl ListFn<'a, PostView, (PostQuery<'a>, &'a Site)>, > { let is_creator_banned_from_community = exists( @@ -142,6 +141,7 @@ fn queries<'a>() -> Queries< .single_value() }; + // TODO maybe this should go to localuser also let all_joins = move |query: post_aggregates::BoxedQuery<'a, Pg>, my_person_id: Option| { let is_local_user_banned_from_community_selection: Box< @@ -250,52 +250,56 @@ fn queries<'a>() -> Queries< )) }; - let read = - move |mut conn: DbConn<'a>, - (post_id, my_person_id, is_mod_or_admin): (PostId, Option, bool)| async move { - // The left join below will return None in this case - let person_id_join = my_person_id.unwrap_or(PersonId(-1)); + let read = move |mut conn: DbConn<'a>, + (post_id, my_local_user, is_mod_or_admin): ( + PostId, + Option<&'a LocalUser>, + bool, + )| async move { + // The left join below will return None in this case + let my_person_id = my_local_user.person_id(); + let person_id_join = my_person_id.unwrap_or(PersonId(-1)); - let mut query = all_joins( - post_aggregates::table - .filter(post_aggregates::post_id.eq(post_id)) - .into_boxed(), - my_person_id, - ); + let mut query = all_joins( + post_aggregates::table + .filter(post_aggregates::post_id.eq(post_id)) + .into_boxed(), + my_person_id, + ); - // Hide deleted and removed for non-admins or mods - if !is_mod_or_admin { - query = query - .filter( - community::removed - .eq(false) - .or(post::creator_id.eq(person_id_join)), - ) - .filter( - post::removed - .eq(false) - .or(post::creator_id.eq(person_id_join)), - ) - // users can see their own deleted posts - .filter( - community::deleted - .eq(false) - .or(post::creator_id.eq(person_id_join)), - ) - .filter( - post::deleted - .eq(false) - .or(post::creator_id.eq(person_id_join)), - ); - } + // Hide deleted and removed for non-admins or mods + if !is_mod_or_admin { + query = query + .filter( + community::removed + .eq(false) + .or(post::creator_id.eq(person_id_join)), + ) + .filter( + post::removed + .eq(false) + .or(post::creator_id.eq(person_id_join)), + ) + // users can see their own deleted posts + .filter( + community::deleted + .eq(false) + .or(post::creator_id.eq(person_id_join)), + ) + .filter( + post::deleted + .eq(false) + .or(post::creator_id.eq(person_id_join)), + ); + } - query = visible_communities_only(my_person_id, query); + query = my_local_user.visible_communities_only(query); - Commented::new(query) - .text("PostView::read") - .first(&mut conn) - .await - }; + Commented::new(query) + .text("PostView::read") + .first(&mut conn) + .await + }; let list = move |mut conn: DbConn<'a>, (options, site): (PostQuery<'a>, &'a Site)| async move { // The left join below will return None in this case @@ -437,7 +441,7 @@ fn queries<'a>() -> Queries< } }; - query = visible_communities_only(options.local_user.person_id(), query); + query = options.local_user.visible_communities_only(query); // Dont filter blocks or missing languages for moderator view type if let (Some(person_id), false) = ( @@ -552,14 +556,14 @@ fn queries<'a>() -> Queries< } impl PostView { - pub async fn read( + pub async fn read<'a>( pool: &mut DbPool<'_>, post_id: PostId, - my_person_id: Option, + my_local_user: Option<&'a LocalUser>, is_mod_or_admin: bool, ) -> Result, Error> { queries() - .read(pool, (post_id, my_person_id, is_mod_or_admin)) + .read(pool, (post_id, my_local_user, is_mod_or_admin)) .await } } @@ -938,7 +942,7 @@ mod tests { let post_listing_single_with_person = PostView::read( pool, data.inserted_post.id, - Some(data.local_user_view.person.id), + Some(&data.local_user_view.local_user), false, ) .await? @@ -1067,7 +1071,7 @@ mod tests { let post_listing_single_with_person = PostView::read( pool, data.inserted_post.id, - Some(data.local_user_view.person.id), + Some(&data.local_user_view.local_user), false, ) .await? @@ -1755,7 +1759,7 @@ mod tests { let authenticated_post = PostView::read( pool, data.inserted_post.id, - Some(data.local_user_view.person.id), + Some(&data.local_user_view.local_user), false, ) .await; @@ -1797,7 +1801,7 @@ mod tests { let post_view = PostView::read( pool, data.inserted_post.id, - Some(inserted_banned_from_comm_local_user.person_id), + Some(&inserted_banned_from_comm_local_user), false, ) .await? @@ -1819,7 +1823,7 @@ mod tests { let post_view = PostView::read( pool, data.inserted_post.id, - Some(data.local_user_view.person.id), + Some(&data.local_user_view.local_user), false, ) .await? diff --git a/crates/db_views_actor/src/community_view.rs b/crates/db_views_actor/src/community_view.rs index 25e76c7b3..7d8a7277f 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -22,27 +22,18 @@ use lemmy_db_schema::{ instance_block, }, source::{community::CommunityFollower, local_user::LocalUser, site::Site}, - utils::{ - fuzzy_search, - limit_and_offset, - visible_communities_only, - DbConn, - DbPool, - ListFn, - Queries, - ReadFn, - }, + utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, ListingType, SortType, }; fn queries<'a>() -> Queries< - impl ReadFn<'a, CommunityView, (CommunityId, Option, bool)>, + impl ReadFn<'a, CommunityView, (CommunityId, Option<&'a LocalUser>, bool)>, impl ListFn<'a, CommunityView, (CommunityQuery<'a>, &'a Site)>, > { - let all_joins = |query: community::BoxedQuery<'a, Pg>, my_person_id: Option| { + let all_joins = |query: community::BoxedQuery<'a, Pg>, my_local_user: Option<&'a LocalUser>| { // The left join below will return None in this case - let person_id_join = my_person_id.unwrap_or(PersonId(-1)); + let person_id_join = my_local_user.person_id().unwrap_or(PersonId(-1)); query .inner_join(community_aggregates::table) @@ -89,14 +80,14 @@ fn queries<'a>() -> Queries< .and(community::deleted.eq(false)); let read = move |mut conn: DbConn<'a>, - (community_id, my_person_id, is_mod_or_admin): ( + (community_id, my_local_user, is_mod_or_admin): ( CommunityId, - Option, + Option<&'a LocalUser>, bool, )| async move { let mut query = all_joins( community::table.find(community_id).into_boxed(), - my_person_id, + my_local_user, ) .select(selection); @@ -105,7 +96,7 @@ fn queries<'a>() -> Queries< query = query.filter(not_removed_or_deleted); } - query = visible_communities_only(my_person_id, query); + query = my_local_user.visible_communities_only(query); query.first(&mut conn).await }; @@ -116,11 +107,7 @@ fn queries<'a>() -> Queries< // The left join below will return None in this case let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1)); - let mut query = all_joins( - community::table.into_boxed(), - options.local_user.person_id(), - ) - .select(selection); + let mut query = all_joins(community::table.into_boxed(), options.local_user).select(selection); if let Some(search_term) = options.search_term { let searcher = fuzzy_search(&search_term); @@ -173,7 +160,7 @@ fn queries<'a>() -> Queries< query = query.filter(community::nsfw.eq(false)); } - query = visible_communities_only(options.local_user.person_id(), query); + query = options.local_user.visible_communities_only(query); let (limit, offset) = limit_and_offset(options.page, options.limit)?; query @@ -187,14 +174,14 @@ fn queries<'a>() -> Queries< } impl CommunityView { - pub async fn read( + pub async fn read<'a>( pool: &mut DbPool<'_>, community_id: CommunityId, - my_person_id: Option, + my_local_user: Option<&'a LocalUser>, is_mod_or_admin: bool, ) -> Result, Error> { queries() - .read(pool, (community_id, my_person_id, is_mod_or_admin)) + .read(pool, (community_id, my_local_user, is_mod_or_admin)) .await } @@ -388,7 +375,7 @@ mod tests { let authenticated_community = CommunityView::read( pool, data.inserted_community.id, - Some(data.local_user.person_id), + Some(&data.local_user), false, ) .await; diff --git a/migrations/2024-06-24-000000_ap_id_triggers/down.sql b/migrations/2024-06-24-000000_ap_id_triggers/down.sql new file mode 100644 index 000000000..72312eccf --- /dev/null +++ b/migrations/2024-06-24-000000_ap_id_triggers/down.sql @@ -0,0 +1,9 @@ +ALTER TABLE comment + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); + +ALTER TABLE post + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); + +ALTER TABLE private_message + ALTER COLUMN ap_id SET DEFAULT generate_unique_changeme (); + diff --git a/migrations/2024-06-24-000000_ap_id_triggers/up.sql b/migrations/2024-06-24-000000_ap_id_triggers/up.sql new file mode 100644 index 000000000..86e266d46 --- /dev/null +++ b/migrations/2024-06-24-000000_ap_id_triggers/up.sql @@ -0,0 +1,9 @@ +ALTER TABLE comment + ALTER COLUMN ap_id DROP DEFAULT; + +ALTER TABLE post + ALTER COLUMN ap_id DROP DEFAULT; + +ALTER TABLE private_message + ALTER COLUMN ap_id DROP DEFAULT; + diff --git a/migrations/2024-07-01-014711_exponential_controversy/down.sql b/migrations/2024-07-01-014711_exponential_controversy/down.sql new file mode 100644 index 000000000..15a7f296a --- /dev/null +++ b/migrations/2024-07-01-014711_exponential_controversy/down.sql @@ -0,0 +1,17 @@ +UPDATE + post_aggregates +SET + controversy_rank = CASE WHEN downvotes <= 0 + OR upvotes <= 0 THEN + 0 + ELSE + (upvotes + downvotes) * CASE WHEN upvotes > downvotes THEN + downvotes::float / upvotes::float + ELSE + upvotes::float / downvotes::float + END + END +WHERE + upvotes > 0 + AND downvotes > 0; + diff --git a/migrations/2024-07-01-014711_exponential_controversy/up.sql b/migrations/2024-07-01-014711_exponential_controversy/up.sql new file mode 100644 index 000000000..87a700de3 --- /dev/null +++ b/migrations/2024-07-01-014711_exponential_controversy/up.sql @@ -0,0 +1,17 @@ +UPDATE + post_aggregates +SET + controversy_rank = CASE WHEN downvotes <= 0 + OR upvotes <= 0 THEN + 0 + ELSE + (upvotes + downvotes) ^ CASE WHEN upvotes > downvotes THEN + downvotes::float / upvotes::float + ELSE + upvotes::float / downvotes::float + END + END +WHERE + upvotes > 0 + AND downvotes > 0; + diff --git a/scripts/lint.sh b/scripts/lint.sh index 7a93b5f54..20d89acb4 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -12,6 +12,6 @@ cargo +nightly fmt taplo format # Format sql files -find migrations -type f -name '*.sql' -exec pg_format -i {} + +find migrations crates/db_schema/replaceable_schema -type f -name '*.sql' -exec pg_format -i {} + cargo clippy --workspace --fix --allow-staged --allow-dirty --tests --all-targets --all-features -- -D warnings diff --git a/src/lib.rs b/src/lib.rs index c51072bcc..3c3633b75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use prometheus_metrics::serve_prometheus; use reqwest_middleware::ClientBuilder; use reqwest_tracing::TracingMiddleware; use serde_json::json; -use std::{env, ops::Deref}; +use std::{env, ops::Deref, time::Duration}; use tokio::signal::unix::SignalKind; use tracing::subscriber::set_global_default; use tracing_actix_web::TracingLogger; @@ -64,6 +64,13 @@ use tracing_log::LogTracer; use tracing_subscriber::{filter::Targets, layer::SubscriberExt, Layer, Registry}; use url::Url; +/// Timeout for HTTP requests while sending activities. A longer timeout provides better +/// compatibility with other ActivityPub software that might allocate more time for synchronous +/// processing of incoming activities. This timeout should be slightly longer than the time we +/// expect a remote server to wait before aborting processing on its own to account for delays from +/// establishing the HTTP connection and sending the request itself. +const ACTIVITY_SENDING_TIMEOUT: Duration = Duration::from_secs(125); + #[derive(Parser, Debug)] #[command( version, @@ -173,8 +180,8 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> { serve_prometheus(prometheus, context.clone())?; } - let mut federation_config = FederationConfig::builder(); - federation_config + let mut federation_config_builder = FederationConfig::builder(); + federation_config_builder .domain(SETTINGS.hostname.clone()) .app_data(context.clone()) .client(client.clone()) @@ -184,9 +191,9 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> { .url_verifier(Box::new(VerifyUrlData(context.inner_pool().clone()))); if local_site.federation_signed_fetch { let site: ApubSite = site_view.site.into(); - federation_config.signed_fetch_actor(&site); + federation_config_builder.signed_fetch_actor(&site); } - let federation_config = federation_config.build().await?; + let federation_config = federation_config_builder.build().await?; MATCH_OUTGOING_ACTIVITIES .set(Box::new(move |d, c| { @@ -209,13 +216,23 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> { } else { None }; - let federate = (!args.disable_activity_sending).then(|| { + + // This FederationConfig instance is exclusively used to send activities, so we can safely + // increase the timeout without affecting timeouts for resolving objects anywhere. + let federation_sender_config = if !args.disable_activity_sending { + let mut federation_sender_config = federation_config_builder.clone(); + federation_sender_config.request_timeout(ACTIVITY_SENDING_TIMEOUT); + Some(federation_sender_config.build().await?) + } else { + None + }; + let federate = federation_sender_config.map(|cfg| { SendManager::run( Opts { process_index: args.federate_process_index, process_count: args.federate_process_count, }, - federation_config, + cfg, SETTINGS.federation.clone(), ) }); diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index 2885b5f74..ae6187a53 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -559,9 +559,9 @@ mod tests { #[tokio::test] #[serial] - async fn test_nodeinfo_voyager_lemmy_ml() -> LemmyResult<()> { + async fn test_nodeinfo_lemmy_ml() -> LemmyResult<()> { let client = ClientBuilder::new(client_builder(&Settings::default()).build()?).build(); - let form = build_update_instance_form("voyager.lemmy.ml", &client) + let form = build_update_instance_form("lemmy.ml", &client) .await .ok_or(LemmyErrorType::CouldntFindObject)?; assert_eq!(