X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fapi_crud%2Fsrc%2Fpost%2Fread.rs;h=d37b1a5825819cb875325cbb9b6660fab312d72e;hb=c8063f3267cf2b3622f1fdc69128c6b55feefbbc;hp=8d049e70ae073db8a8b0a3e3a2ede219a891f610;hpb=4a23ee4d8b1c73db38b48b43e2a1e99efd658b89;p=lemmy.git diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 8d049e70..d37b1a58 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -1,204 +1,115 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ - blocking, - check_private_instance, - get_local_user_view_from_jwt_opt, - mark_post_as_read, - post::*, - resolve_actor_identifier, + context::LemmyContext, + post::{GetPost, GetPostResponse}, + utils::{ + check_private_instance, + is_mod_or_admin_opt, + local_user_view_from_jwt_opt, + mark_post_as_read, + }, }; use lemmy_db_schema::{ - from_opt_str_to_opt_enum, - source::community::Community, - traits::DeleteableOrRemoveable, - ListingType, - SortType, + aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm}, + source::{comment::Comment, local_site::LocalSite, post::Post}, + traits::Crud, }; -use lemmy_db_views::{ - comment_view::CommentQueryBuilder, - post_view::{PostQueryBuilder, PostView}, -}; -use lemmy_db_views_actor::{ - community_moderator_view::CommunityModeratorView, - community_view::CommunityView, -}; -use lemmy_utils::{ConnectionId, LemmyError}; -use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext}; - -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetPost { - type Response = GetPostResponse; - - #[tracing::instrument(skip(context, _websocket_id))] - async fn perform( - &self, - context: &Data, - _websocket_id: Option, - ) -> Result { - let data: &GetPost = self; - let local_user_view = - get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) - .await?; - - check_private_instance(&local_user_view, context.pool()).await?; - - let show_bot_accounts = local_user_view - .as_ref() - .map(|t| t.local_user.show_bot_accounts); - let person_id = local_user_view.map(|u| u.person.id); - - let id = data.id; - let mut post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, id, person_id) - }) - .await? - .map_err(LemmyError::from) - .map_err(|e| e.with_message("couldnt_find_post"))?; - - // Mark the post as read - if let Some(person_id) = person_id { - mark_post_as_read(person_id, id, context.pool()).await?; - } - - let id = data.id; - let mut comments = blocking(context.pool(), move |conn| { - CommentQueryBuilder::create(conn) - .my_person_id(person_id) - .show_bot_accounts(show_bot_accounts) - .post_id(id) - .limit(9999) - .list() - }) - .await??; - - // Necessary for the sidebar - let community_id = post_view.community.id; - let mut community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, person_id) - }) - .await? - .map_err(LemmyError::from) - .map_err(|e| e.with_message("couldnt_find_community"))?; - - // Blank out deleted or removed info for non-logged in users - if person_id.is_none() { - if post_view.post.deleted || post_view.post.removed { - post_view.post = post_view.post.blank_out_deleted_or_removed_info(); - } - - for cv in comments - .iter_mut() - .filter(|cv| cv.comment.deleted || cv.comment.removed) - { - cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info(); - } - if community_view.community.deleted || community_view.community.removed { - community_view.community = community_view.community.blank_out_deleted_or_removed_info(); - } - } - - let moderators = blocking(context.pool(), move |conn| { - CommunityModeratorView::for_community(conn, community_id) - }) - .await??; - - let online = context - .chat_server() - .send(GetPostUsersOnline { post_id: data.id }) +use lemmy_db_views::{post_view::PostQuery, structs::PostView}; +use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; +use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; + +#[tracing::instrument(skip(context))] +pub async fn get_post( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(&mut context.pool()).await?; + + check_private_instance(&local_user_view, &local_site)?; + + let person_id = local_user_view.as_ref().map(|u| u.person.id); + + // I'd prefer fetching the post_view by a comment join, but it adds a lot of boilerplate + let post_id = if let Some(id) = data.id { + id + } else if let Some(comment_id) = data.comment_id { + Comment::read(&mut context.pool(), comment_id) .await - .unwrap_or(1); - - // Return the jwt - Ok(GetPostResponse { - post_view, - community_view, - comments, - moderators, - online, - }) + .with_lemmy_type(LemmyErrorType::CouldntFindPost)? + .post_id + } else { + Err(LemmyErrorType::CouldntFindPost)? + }; + + // Check to see if the person is a mod or admin, to show deleted / removed + let community_id = Post::read(&mut context.pool(), post_id).await?.community_id; + let is_mod_or_admin = is_mod_or_admin_opt( + &mut context.pool(), + local_user_view.as_ref(), + Some(community_id), + ) + .await + .is_ok(); + + let post_view = PostView::read(&mut context.pool(), post_id, person_id, is_mod_or_admin) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; + + // Mark the post as read + let post_id = post_view.post.id; + if let Some(person_id) = person_id { + mark_post_as_read(person_id, post_id, &mut context.pool()).await?; } -} - -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetPosts { - type Response = GetPostsResponse; - - #[tracing::instrument(skip(context, _websocket_id))] - async fn perform( - &self, - context: &Data, - _websocket_id: Option, - ) -> Result { - let data: &GetPosts = self; - let local_user_view = - get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret()) - .await?; - - check_private_instance(&local_user_view, context.pool()).await?; - - let person_id = local_user_view.to_owned().map(|l| l.person.id); - let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw); - let show_bot_accounts = local_user_view - .as_ref() - .map(|t| t.local_user.show_bot_accounts); - let show_read_posts = local_user_view - .as_ref() - .map(|t| t.local_user.show_read_posts); - - let sort: Option = from_opt_str_to_opt_enum(&data.sort); - let listing_type: Option = from_opt_str_to_opt_enum(&data.type_); - - let page = data.page; - let limit = data.limit; - let community_id = data.community_id; - let community_actor_id = if let Some(name) = &data.community_name { - resolve_actor_identifier::(name, context.pool()) - .await - .ok() - .map(|c| c.actor_id) - } else { - None + // Necessary for the sidebar subscribed + let community_view = CommunityView::read( + &mut context.pool(), + community_id, + person_id, + is_mod_or_admin, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + + // Insert into PersonPostAggregates + // to update the read_comments count + if let Some(person_id) = person_id { + let read_comments = post_view.counts.comments; + let person_post_agg_form = PersonPostAggregatesForm { + person_id, + post_id, + read_comments, + ..PersonPostAggregatesForm::default() }; - let saved_only = data.saved_only; - - let mut posts = blocking(context.pool(), move |conn| { - PostQueryBuilder::create(conn) - .listing_type(listing_type) - .sort(sort) - .show_nsfw(show_nsfw) - .show_bot_accounts(show_bot_accounts) - .show_read_posts(show_read_posts) - .community_id(community_id) - .community_actor_id(community_actor_id) - .saved_only(saved_only) - .my_person_id(person_id) - .page(page) - .limit(limit) - .list() - }) - .await? - .map_err(LemmyError::from) - .map_err(|e| e.with_message("couldnt_get_posts"))?; + PersonPostAggregates::upsert(&mut context.pool(), &person_post_agg_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; + } - // Blank out deleted or removed info for non-logged in users - if person_id.is_none() { - for pv in posts - .iter_mut() - .filter(|p| p.post.deleted || p.post.removed) - { - pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info(); - } + let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - for pv in posts - .iter_mut() - .filter(|p| p.community.deleted || p.community.removed) - { - pv.community = pv.to_owned().community.blank_out_deleted_or_removed_info(); - } + // 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()), + ..Default::default() } - - Ok(GetPostsResponse { posts }) - } + .list(&mut context.pool()) + .await?; + + // Don't return this post as one of the cross_posts + x_posts.retain(|x| x.post.id != post_id); + x_posts + } else { + Vec::new() + }; + + // Return the jwt + Ok(Json(GetPostResponse { + post_view, + community_view, + moderators, + cross_posts, + })) }