diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs index e36e86b4c..7fb4b83f9 100644 --- a/crates/api/src/local_user.rs +++ b/crates/api/src/local_user.rs @@ -240,6 +240,7 @@ impl Perform for SaveUserSettings { default_listing_type, lang: data.lang.to_owned(), show_avatars: data.show_avatars, + show_read_posts: data.show_read_posts, send_notifications_to_email: data.send_notifications_to_email, }; diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index 34c9c4116..f0e4d91fa 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -6,6 +6,7 @@ use lemmy_api_common::{ check_downvotes_enabled, get_local_user_view_from_jwt, is_mod_or_admin, + mark_post_as_read, post::*, }; use lemmy_apub::{ApubLikeableType, ApubObjectType}; @@ -69,6 +70,9 @@ impl Perform for CreatePostLike { .await?; } + // Mark the post as read + mark_post_as_read(person_id, post_id, context.pool()).await?; + let post_id = data.post_id; let person_id = local_user_view.person.id; let post_view = blocking(context.pool(), move |conn| { @@ -269,6 +273,9 @@ impl Perform for SavePost { }) .await??; + // Mark the post as read + mark_post_as_read(person_id, post_id, context.pool()).await?; + Ok(PostResponse { post_view }) } } diff --git a/crates/api/src/site.rs b/crates/api/src/site.rs index c55ac6645..dab458304 100644 --- a/crates/api/src/site.rs +++ b/crates/api/src/site.rs @@ -9,8 +9,6 @@ use lemmy_api_common::{ get_local_user_view_from_jwt_opt, is_admin, site::*, - user_show_bot_accounts, - user_show_nsfw, }; use lemmy_apub::fetcher::search::search_by_apub_id; use lemmy_db_queries::{ @@ -145,8 +143,13 @@ impl Perform for Search { let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let show_nsfw = user_show_nsfw(&local_user_view); - let show_bot_accounts = user_show_bot_accounts(&local_user_view); + 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 person_id = local_user_view.map(|u| u.person.id); @@ -173,6 +176,7 @@ impl Perform for Search { .sort(sort) .show_nsfw(show_nsfw) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .listing_type(listing_type) .community_id(community_id) .community_name(community_name) @@ -236,6 +240,7 @@ impl Perform for Search { .sort(sort) .show_nsfw(show_nsfw) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .listing_type(listing_type) .community_id(community_id) .community_name(community_name) @@ -307,6 +312,7 @@ impl Perform for Search { .sort(sort) .show_nsfw(show_nsfw) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .listing_type(listing_type) .my_person_id(person_id) .community_id(community_id) diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index 1a644b7d4..f2b41be50 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -14,6 +14,7 @@ use lemmy_db_queries::{ }, Crud, DbPool, + Readable, }; use lemmy_db_schema::{ source::{ @@ -21,7 +22,7 @@ use lemmy_db_schema::{ community::{Community, CommunityModerator}, person::Person, person_mention::{PersonMention, PersonMentionForm}, - post::Post, + post::{Post, PostRead, PostReadForm}, site::Site, }, CommunityId, @@ -236,28 +237,26 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { Ok(()) } -/// A helper method for showing the bot account -pub fn user_show_bot_accounts(local_user_view: &Option) -> bool { - match local_user_view { - Some(uv) => uv.to_owned().local_user.show_bot_accounts, - None => true, - } -} - -/// A helper method for showing nsfw -pub fn user_show_nsfw(local_user_view: &Option) -> bool { - match &local_user_view { - Some(uv) => uv.local_user.show_nsfw, - None => false, - } -} - pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result { blocking(pool, move |conn| Post::read(conn, post_id)) .await? .map_err(|_| ApiError::err("couldnt_find_post").into()) } +pub async fn mark_post_as_read( + person_id: PersonId, + post_id: PostId, + pool: &DbPool, +) -> Result { + let post_read_form = PostReadForm { post_id, person_id }; + + blocking(pool, move |conn| { + PostRead::mark_as_read(conn, &post_read_form) + }) + .await? + .map_err(|_| ApiError::err("couldnt_mark_post_as_read").into()) +} + pub async fn get_local_user_view_from_jwt( jwt: &str, pool: &DbPool, diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 8349f2a1f..12cc5deeb 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -62,6 +62,7 @@ pub struct SaveUserSettings { pub send_notifications_to_email: Option, pub bot_account: Option, pub show_bot_accounts: Option, + pub show_read_posts: Option, pub auth: String, } diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index f82b97481..12ccbd5a1 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -1,11 +1,6 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{ - blocking, - comment::*, - get_local_user_view_from_jwt_opt, - user_show_bot_accounts, -}; +use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt}; use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType}; use lemmy_db_views::comment_view::CommentQueryBuilder; use lemmy_utils::{ApiError, ConnectionId, LemmyError}; @@ -23,7 +18,9 @@ impl PerformCrud for GetComments { let data: &GetComments = &self; let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let show_bot_accounts = user_show_bot_accounts(&local_user_view); + 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 sort: Option = from_opt_str_to_opt_enum(&data.sort); diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 3a2311a76..835518a14 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -1,6 +1,12 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{blocking, check_community_ban, get_local_user_view_from_jwt, post::*}; +use lemmy_api_common::{ + blocking, + check_community_ban, + get_local_user_view_from_jwt, + mark_post_as_read, + post::*, +}; use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType}; use lemmy_db_queries::{source::post::Post_, Crud, Likeable}; use lemmy_db_schema::source::post::*; @@ -81,9 +87,11 @@ impl PerformCrud for CreatePost { .await?; // They like their own post by default + let person_id = local_user_view.person.id; + let post_id = inserted_post.id; let like_form = PostLikeForm { - post_id: inserted_post.id, - person_id: local_user_view.person.id, + post_id, + person_id, score: 1, }; @@ -92,6 +100,9 @@ impl PerformCrud for CreatePost { return Err(ApiError::err("couldnt_like_post").into()); } + // Mark the post as read + mark_post_as_read(person_id, post_id, context.pool()).await?; + updated_post .send_like(&local_user_view.person, context) .await?; diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 14c6cad5f..d49764bba 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -1,12 +1,6 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{ - blocking, - get_local_user_view_from_jwt_opt, - post::*, - user_show_bot_accounts, - user_show_nsfw, -}; +use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, mark_post_as_read, post::*}; use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType}; use lemmy_db_views::{ comment_view::CommentQueryBuilder, @@ -31,8 +25,9 @@ impl PerformCrud for GetPost { let data: &GetPost = &self; let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let show_bot_accounts = user_show_bot_accounts(&local_user_view); - + 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; @@ -42,6 +37,11 @@ impl PerformCrud for GetPost { .await? .map_err(|_| ApiError::err("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 comments = blocking(context.pool(), move |conn| { CommentQueryBuilder::create(conn) @@ -97,8 +97,13 @@ impl PerformCrud for GetPosts { let person_id = local_user_view.to_owned().map(|l| l.person.id); - let show_nsfw = user_show_nsfw(&local_user_view); - let show_bot_accounts = user_show_bot_accounts(&local_user_view); + 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_); @@ -115,6 +120,7 @@ impl PerformCrud for GetPosts { .sort(sort) .show_nsfw(show_nsfw) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .community_id(community_id) .community_name(community_name) .saved_only(saved_only) diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 097555561..d7aae65f0 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -130,6 +130,7 @@ impl PerformCrud for Register { lang: Some("browser".into()), show_avatars: Some(true), show_scores: Some(true), + show_read_posts: Some(true), send_notifications_to_email: Some(false), }; diff --git a/crates/api_crud/src/user/read.rs b/crates/api_crud/src/user/read.rs index 39431128a..132bdd78f 100644 --- a/crates/api_crud/src/user/read.rs +++ b/crates/api_crud/src/user/read.rs @@ -1,12 +1,6 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{ - blocking, - get_local_user_view_from_jwt_opt, - person::*, - user_show_bot_accounts, - user_show_nsfw, -}; +use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*}; use lemmy_db_queries::{from_opt_str_to_opt_enum, source::person::Person_, SortType}; use lemmy_db_schema::source::person::*; use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder}; @@ -30,8 +24,13 @@ impl PerformCrud for GetPersonDetails { let data: &GetPersonDetails = &self; let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let show_nsfw = user_show_nsfw(&local_user_view); - let show_bot_accounts = user_show_bot_accounts(&local_user_view); + 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); @@ -71,6 +70,7 @@ impl PerformCrud for GetPersonDetails { .sort(sort) .show_nsfw(show_nsfw) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .saved_only(saved_only) .community_id(community_id) .my_person_id(person_id) diff --git a/crates/db_queries/src/source/local_user.rs b/crates/db_queries/src/source/local_user.rs index 43a5c7727..2cd347e5c 100644 --- a/crates/db_queries/src/source/local_user.rs +++ b/crates/db_queries/src/source/local_user.rs @@ -26,6 +26,7 @@ mod safe_settings_type { validator_time, show_bot_accounts, show_scores, + show_read_posts, ); impl ToSafeSettings for LocalUser { @@ -47,6 +48,7 @@ mod safe_settings_type { validator_time, show_bot_accounts, show_scores, + show_read_posts, ) } } diff --git a/crates/db_queries/src/source/post.rs b/crates/db_queries/src/source/post.rs index 0205dc954..9f2d2f9b3 100644 --- a/crates/db_queries/src/source/post.rs +++ b/crates/db_queries/src/source/post.rs @@ -243,6 +243,9 @@ impl Readable for PostRead { use lemmy_db_schema::schema::post_read::dsl::*; insert_into(post_read) .values(post_read_form) + .on_conflict((post_id, person_id)) + .do_update() + .set(post_read_form) .get_result::(conn) } diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index a70083981..4a52b310d 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -155,6 +155,7 @@ table! { validator_time -> Timestamp, show_bot_accounts -> Bool, show_scores -> Bool, + show_read_posts -> Bool, } } diff --git a/crates/db_schema/src/source/local_user.rs b/crates/db_schema/src/source/local_user.rs index 64afb49a4..77e0c0ceb 100644 --- a/crates/db_schema/src/source/local_user.rs +++ b/crates/db_schema/src/source/local_user.rs @@ -18,6 +18,7 @@ pub struct LocalUser { pub validator_time: chrono::NaiveDateTime, pub show_bot_accounts: bool, pub show_scores: bool, + pub show_read_posts: bool, } // TODO redo these, check table defaults @@ -36,6 +37,7 @@ pub struct LocalUserForm { pub send_notifications_to_email: Option, pub show_bot_accounts: Option, pub show_scores: Option, + pub show_read_posts: Option, } /// A local user view that removes password encrypted @@ -55,4 +57,5 @@ pub struct LocalUserSettings { pub validator_time: chrono::NaiveDateTime, pub show_bot_accounts: bool, pub show_scores: bool, + pub show_read_posts: bool, } diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index fb8f07336..1d8ea80e6 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -165,8 +165,8 @@ pub struct PostQueryBuilder<'a> { url_search: Option, show_nsfw: Option, show_bot_accounts: Option, + show_read_posts: Option, saved_only: Option, - unread_only: Option, page: Option, limit: Option, } @@ -185,8 +185,8 @@ impl<'a> PostQueryBuilder<'a> { url_search: None, show_nsfw: None, show_bot_accounts: None, + show_read_posts: None, saved_only: None, - unread_only: None, page: None, limit: None, } @@ -242,6 +242,11 @@ impl<'a> PostQueryBuilder<'a> { self } + pub fn show_read_posts>(mut self, show_read_posts: T) -> Self { + self.show_read_posts = show_read_posts.get_optional(); + self + } + pub fn saved_only>(mut self, saved_only: T) -> Self { self.saved_only = saved_only.get_optional(); self @@ -364,12 +369,12 @@ impl<'a> PostQueryBuilder<'a> { query = query.filter(person::bot_account.eq(false)); }; - if self.saved_only.unwrap_or(false) { - query = query.filter(post_saved::id.is_not_null()); + if !self.show_read_posts.unwrap_or(true) { + query = query.filter(post_read::id.is_null()); }; - if self.unread_only.unwrap_or(false) { - query = query.filter(post_read::id.is_not_null()); + if self.saved_only.unwrap_or(false) { + query = query.filter(post_saved::id.is_not_null()); }; query = match self.sort.unwrap_or(SortType::Hot) { diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index a4f6a45a0..06b9ac13a 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -230,11 +230,13 @@ fn get_feed_front( let local_user = LocalUser::read(&conn, local_user_id)?; let person_id = local_user.person_id; let show_bot_accounts = local_user.show_bot_accounts; + let show_read_posts = local_user.show_read_posts; let posts = PostQueryBuilder::create(&conn) .listing_type(ListingType::Subscribed) .my_person_id(person_id) .show_bot_accounts(show_bot_accounts) + .show_read_posts(show_read_posts) .sort(*sort_type) .list()?; diff --git a/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql b/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql new file mode 100644 index 000000000..2aa275147 --- /dev/null +++ b/migrations/2021-04-24-174047_add_show_read_post_setting/down.sql @@ -0,0 +1 @@ +alter table local_user drop column show_read_posts; diff --git a/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql b/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql new file mode 100644 index 000000000..74b5398c3 --- /dev/null +++ b/migrations/2021-04-24-174047_add_show_read_post_setting/up.sql @@ -0,0 +1 @@ +alter table local_user add column show_read_posts boolean default true not null;