diff --git a/crates/api/src/post/block.rs b/crates/api/src/post/block.rs new file mode 100644 index 0000000000..2d1baa9580 --- /dev/null +++ b/crates/api/src/post/block.rs @@ -0,0 +1,25 @@ +use lemmy_api_common::{post::{BlockKeywordForPost}, context::LemmyContext, SuccessResponse}; +use lemmy_db_views::structs::LocalUserView; +use activitypub_federation::config::Data; +use actix_web::web::Json; +use lemmy_utils::error::LemmyResult; +use lemmy_db_schema::source::post_keyword_block::{PostKeywordBlock, PostKeywordBlockForm}; + +pub async fn user_block_keyword_for_posts( + data: Json, + context: Data, + local_user_view: LocalUserView +) -> LemmyResult>{ + + let person_id = local_user_view.person.id; + let post_block_keyword_form = PostKeywordBlockForm { + person_id, + keyword: data.keyword.clone(), + }; + if(data.block){ + PostKeywordBlock::block_keyword(&mut context.pool(), &post_block_keyword_form).await?; + } else { + PostKeywordBlock::unblock_keyword(&mut context.pool(), &post_block_keyword_form).await?; + } + Ok(Json(SuccessResponse::default())) +} \ No newline at end of file diff --git a/crates/api/src/post/mod.rs b/crates/api/src/post/mod.rs index 97410f097f..340dd0401b 100644 --- a/crates/api/src/post/mod.rs +++ b/crates/api/src/post/mod.rs @@ -7,3 +7,4 @@ pub mod lock; pub mod mark_many_read; pub mod mark_read; pub mod save; +pub mod block; diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index 405de3a92d..c53efc4f01 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -366,3 +366,12 @@ pub struct ListPostLikes { pub struct ListPostLikesResponse { pub post_likes: Vec, } + +#[derive(Debug,Serialize,Deserialize,Clone)] +#[cfg_attr(feature = "full", derive(TS))] +#[cfg_attr(feature = "full", ts(export))] +pub struct BlockKeywordForPost { + pub keyword: String, + pub block : bool, +} + diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 7f1000b14e..3df7f5ff52 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -65,6 +65,7 @@ use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; #[cfg(feature = "full")] use ts_rs::TS; +use lemmy_db_schema::source::post_keyword_block::PostKeywordBlock; #[skip_serializing_none] #[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)] @@ -479,6 +480,7 @@ pub struct MyUserInfo { pub community_blocks: Vec, pub instance_blocks: Vec, pub person_blocks: Vec, + pub post_keyword_blocks: Vec, pub discussion_languages: Vec, } diff --git a/crates/api_crud/src/user/my_user.rs b/crates/api_crud/src/user/my_user.rs index f7a92eb997..7d12963af3 100644 --- a/crates/api_crud/src/user/my_user.rs +++ b/crates/api_crud/src/user/my_user.rs @@ -6,6 +6,7 @@ use lemmy_db_schema::source::{ instance_block::InstanceBlock, person_block::PersonBlock, }; +use lemmy_db_schema::source::post_keyword_block::PostKeywordBlock; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::{CommunityFollowerView, CommunityModeratorView}; use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; @@ -22,12 +23,13 @@ pub async fn get_my_user( let local_user_id = local_user_view.local_user.id; let pool = &mut context.pool(); - let (follows, community_blocks, instance_blocks, person_blocks, moderates, discussion_languages) = + let (follows, community_blocks, instance_blocks, person_blocks, post_keyword_blocks, moderates, discussion_languages) = lemmy_db_schema::try_join_with_pool!(pool => ( |pool| CommunityFollowerView::for_person(pool, person_id), |pool| CommunityBlock::for_person(pool, person_id), |pool| InstanceBlock::for_person(pool, person_id), |pool| PersonBlock::for_person(pool, person_id), + |pool| PostKeywordBlock::for_person(pool, person_id), |pool| CommunityModeratorView::for_person(pool, person_id, Some(&local_user_view.local_user)), |pool| LocalUserLanguage::read(pool, local_user_id) )) @@ -40,6 +42,7 @@ pub async fn get_my_user( community_blocks, instance_blocks, person_blocks, + post_keyword_blocks, discussion_languages, })) } diff --git a/crates/db_schema/src/impls/mod.rs b/crates/db_schema/src/impls/mod.rs index d4ea47800e..ec00ddaa59 100644 --- a/crates/db_schema/src/impls/mod.rs +++ b/crates/db_schema/src/impls/mod.rs @@ -36,3 +36,4 @@ pub mod registration_application; pub mod secret; pub mod site; pub mod tagline; +mod post_keyword_block; diff --git a/crates/db_schema/src/impls/post_keyword_block.rs b/crates/db_schema/src/impls/post_keyword_block.rs new file mode 100644 index 0000000000..9611cc9df4 --- /dev/null +++ b/crates/db_schema/src/impls/post_keyword_block.rs @@ -0,0 +1,53 @@ +use diesel::{delete, insert_into}; +use diesel::result::Error; +use diesel::prelude::*; +use diesel::QueryDsl; +use diesel_async::RunQueryDsl; +use crate::{ + newtypes::{PersonId}, + schema::post_keyword_block, + source::{ + post_keyword_block::{PostKeywordBlock, PostKeywordBlockForm}, + } +}; +use crate::traits::Crud; +use crate::utils::{get_conn, DbPool}; + +impl PostKeywordBlock { + + + pub async fn for_person( + pool: &mut DbPool<'_>, + person_id: PersonId, + ) -> Result, Error> { + let conn = &mut get_conn(pool).await?; + post_keyword_block::table + .filter(post_keyword_block::person_id.eq(person_id)) + .load::(conn) + .await + } + + pub async fn block_keyword( + pool: &mut DbPool<'_>, + post_keyword_block_form: &PostKeywordBlockForm + ) -> Result { + let conn = &mut get_conn(pool).await?; + insert_into(post_keyword_block::table) + .values(post_keyword_block_form) + .get_result::(conn) + .await + } + + pub async fn unblock_keyword( + pool: &mut DbPool<'_>, + post_keyword_block_form: &PostKeywordBlockForm, + ) -> QueryResult { + let conn = &mut get_conn(pool).await?; + delete(post_keyword_block::table) + .filter(post_keyword_block::person_id.eq(post_keyword_block_form.person_id)) + .filter(post_keyword_block::keyword.eq(&post_keyword_block_form.keyword)) + .execute(conn) + .await + } +} + diff --git a/crates/db_schema/src/newtypes.rs b/crates/db_schema/src/newtypes.rs index c28be8222d..2059896a7a 100644 --- a/crates/db_schema/src/newtypes.rs +++ b/crates/db_schema/src/newtypes.rs @@ -121,6 +121,12 @@ pub struct LanguageId(pub i32); /// The comment reply id. pub struct CommentReplyId(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 comment reply id. +pub struct PostKeywordBlockId(i32); + #[derive( Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default, Ord, PartialOrd, )] diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 66a65d1432..f8117f6738 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -826,6 +826,15 @@ diesel::table! { } } +diesel::table! { + post_keyword_block (id) { + id -> Int4, + #[max_length = 50] + keyword -> Varchar, + person_id -> Int4, + } +} + diesel::table! { private_message (id) { id -> Int4, diff --git a/crates/db_schema/src/source/mod.rs b/crates/db_schema/src/source/mod.rs index 86def96911..e69b6be0f8 100644 --- a/crates/db_schema/src/source/mod.rs +++ b/crates/db_schema/src/source/mod.rs @@ -41,6 +41,7 @@ pub mod registration_application; pub mod secret; pub mod site; pub mod tagline; +pub mod post_keyword_block; /// Default value for columns like [community::Community.inbox_url] which are marked as serde(skip). /// diff --git a/crates/db_schema/src/source/post_keyword_block.rs b/crates/db_schema/src/source/post_keyword_block.rs new file mode 100644 index 0000000000..f7feaebd60 --- /dev/null +++ b/crates/db_schema/src/source/post_keyword_block.rs @@ -0,0 +1,31 @@ +use crate::newtypes::{PersonId, PostKeywordBlockId}; +use serde::{Deserialize, Serialize}; +#[cfg(feature = "full")] +use crate::schema::post_keyword_block; +#[cfg(feature = "full")] +use ts_rs::TS; + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[cfg_attr( + feature = "full", + derive(Queryable, Selectable, Associations, Identifiable,TS) +)] +#[cfg_attr( + feature = "full", + diesel(belongs_to(crate::source::person::Person)) +)] +#[cfg_attr(feature = "full", diesel(table_name = post_keyword_block))] +#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] +#[cfg_attr(feature = "full", ts(export))] +pub struct PostKeywordBlock { + pub id : PostKeywordBlockId, + pub keyword: String, + pub person_id: PersonId, +} + +#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] +#[cfg_attr(feature = "full", diesel(table_name = post_keyword_block))] +pub struct PostKeywordBlockForm { + pub person_id: PersonId, + pub keyword: String, +} \ No newline at end of file diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index c6d1b036f1..2784b514aa 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -32,6 +32,7 @@ use lemmy_db_schema::{ post, post_actions, post_aggregates, + post_keyword_block }, source::{ community::{CommunityFollower, CommunityFollowerState}, @@ -85,6 +86,10 @@ fn queries<'a>() -> Queries< .inner_join(community::table) .inner_join(post::table) .left_join(image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable()))) + .left_join(post_keyword_block::table.on( + post_keyword_block::person_id.eq(my_person_id.unwrap_or(PersonId(-1))), + ), + ) .left_join(actions( community_actions::table, my_person_id, @@ -115,6 +120,7 @@ fn queries<'a>() -> Queries< person::all_columns, community::all_columns, image_details::all_columns.nullable(), + post_keyword_block::keyword, creator_community_actions .field(community_actions::received_ban) .nullable() @@ -351,6 +357,10 @@ fn queries<'a>() -> Queries< query = query.filter(community_actions::blocked.is_null()); query = query.filter(instance_actions::blocked.is_null()); query = query.filter(person_actions::blocked.is_null()); + query = query.filter( + not(post::name.ilike(post_keyword_block::keyword)) + .and(not(post::body.ilike(post_keyword_block::keyword))) + .and(not(post::url.ilike(post_keyword_block::keyword)))); } let (limit, offset) = limit_and_offset(options.page, options.limit)?; diff --git a/src/api_routes_v3.rs b/src/api_routes_v3.rs index eefaf5b871..f07a3273cb 100644 --- a/src/api_routes_v3.rs +++ b/src/api_routes_v3.rs @@ -89,6 +89,7 @@ use lemmy_api::{ }, sitemap::get_sitemap, }; +use lemmy_api::post::block::user_block_keyword_for_posts; use lemmy_api_crud::{ comment::{ create::create_comment, @@ -223,7 +224,8 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) { .route("/report", post().to(create_post_report)) .route("/report/resolve", put().to(resolve_post_report)) .route("/report/list", get().to(list_post_reports)) - .route("/site_metadata", get().to(get_link_metadata)), + .route("/site_metadata", get().to(get_link_metadata)) + .route("/block",post().to(user_block_keyword_for_posts)), ) // Comment .service( diff --git a/src/api_routes_v4.rs b/src/api_routes_v4.rs index a9f71c9da9..818db28b18 100644 --- a/src/api_routes_v4.rs +++ b/src/api_routes_v4.rs @@ -98,6 +98,7 @@ use lemmy_api::{ }, sitemap::get_sitemap, }; +use lemmy_api::post::block::user_block_keyword_for_posts; use lemmy_api_crud::{ comment::{ create::create_comment, @@ -320,7 +321,8 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) { scope("/block") .route("/person", post().to(user_block_person)) .route("/community", post().to(user_block_community)) - .route("/instance", post().to(user_block_instance)), + .route("/instance", post().to(user_block_instance)) + .route("/post",get().to(user_block_keyword_for_posts)), ), ) // User actions