mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-03-28 06:05:29 +00:00
Add media filter setting (#5325)
* Add hide_media filter * Test media is returned when hide_media is false * Add GIN index * SQL fmt * Drop GIN index in migration
This commit is contained in:
parent
3f06317878
commit
099328a5b1
11 changed files with 103 additions and 0 deletions
|
@ -132,6 +132,7 @@ pub async fn save_user_settings(
|
||||||
enable_private_messages: data.enable_private_messages,
|
enable_private_messages: data.enable_private_messages,
|
||||||
collapse_bot_comments: data.collapse_bot_comments,
|
collapse_bot_comments: data.collapse_bot_comments,
|
||||||
auto_mark_fetched_posts_as_read: data.auto_mark_fetched_posts_as_read,
|
auto_mark_fetched_posts_as_read: data.auto_mark_fetched_posts_as_read,
|
||||||
|
hide_media: data.hide_media,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,9 @@ pub struct SaveUserSettings {
|
||||||
/// Whether to automatically mark fetched posts as read.
|
/// Whether to automatically mark fetched posts as read.
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
||||||
|
/// Whether to hide posts containing images/videos.
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub hide_media: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -112,6 +112,9 @@ pub struct GetPosts {
|
||||||
/// If true, then show the nsfw posts (even if your user setting is to hide them)
|
/// If true, then show the nsfw posts (even if your user setting is to hide them)
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
|
/// If false, then show posts with media attached (even if your user setting is to hide them)
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub hide_media: Option<bool>,
|
||||||
/// Whether to automatically mark fetched posts as read.
|
/// Whether to automatically mark fetched posts as read.
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub mark_as_read: Option<bool>,
|
pub mark_as_read: Option<bool>,
|
||||||
|
|
|
@ -45,6 +45,7 @@ pub async fn list_posts(
|
||||||
let show_hidden = data.show_hidden;
|
let show_hidden = data.show_hidden;
|
||||||
let show_read = data.show_read;
|
let show_read = data.show_read;
|
||||||
let show_nsfw = data.show_nsfw;
|
let show_nsfw = data.show_nsfw;
|
||||||
|
let hide_media = data.hide_media;
|
||||||
let no_comments_only = data.no_comments_only;
|
let no_comments_only = data.no_comments_only;
|
||||||
|
|
||||||
let liked_only = data.liked_only;
|
let liked_only = data.liked_only;
|
||||||
|
@ -86,6 +87,7 @@ pub async fn list_posts(
|
||||||
show_hidden,
|
show_hidden,
|
||||||
show_read,
|
show_read,
|
||||||
show_nsfw,
|
show_nsfw,
|
||||||
|
hide_media,
|
||||||
no_comments_only,
|
no_comments_only,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,6 +297,7 @@ pub trait LocalUserOptionHelper {
|
||||||
fn show_read_posts(&self) -> bool;
|
fn show_read_posts(&self) -> bool;
|
||||||
fn is_admin(&self) -> bool;
|
fn is_admin(&self) -> bool;
|
||||||
fn show_nsfw(&self, site: &Site) -> bool;
|
fn show_nsfw(&self, site: &Site) -> bool;
|
||||||
|
fn hide_media(&self) -> bool;
|
||||||
fn visible_communities_only<Q>(&self, query: Q) -> Q
|
fn visible_communities_only<Q>(&self, query: Q) -> Q
|
||||||
where
|
where
|
||||||
Q: diesel::query_dsl::methods::FilterDsl<
|
Q: diesel::query_dsl::methods::FilterDsl<
|
||||||
|
@ -332,6 +333,10 @@ impl LocalUserOptionHelper for Option<&LocalUser> {
|
||||||
.unwrap_or(site.content_warning.is_some())
|
.unwrap_or(site.content_warning.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hide_media(&self) -> bool {
|
||||||
|
self.map(|l| l.hide_media).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use this function for private community checks, but the generics get extremely confusing
|
// TODO: use this function for private community checks, but the generics get extremely confusing
|
||||||
fn visible_communities_only<Q>(&self, query: Q) -> Q
|
fn visible_communities_only<Q>(&self, query: Q) -> Q
|
||||||
where
|
where
|
||||||
|
|
|
@ -513,6 +513,7 @@ diesel::table! {
|
||||||
collapse_bot_comments -> Bool,
|
collapse_bot_comments -> Bool,
|
||||||
default_comment_sort_type -> CommentSortTypeEnum,
|
default_comment_sort_type -> CommentSortTypeEnum,
|
||||||
auto_mark_fetched_posts_as_read -> Bool,
|
auto_mark_fetched_posts_as_read -> Bool,
|
||||||
|
hide_media -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,8 @@ pub struct LocalUser {
|
||||||
pub default_comment_sort_type: CommentSortType,
|
pub default_comment_sort_type: CommentSortType,
|
||||||
/// Whether to automatically mark fetched posts as read.
|
/// Whether to automatically mark fetched posts as read.
|
||||||
pub auto_mark_fetched_posts_as_read: bool,
|
pub auto_mark_fetched_posts_as_read: bool,
|
||||||
|
/// Whether to hide posts containing images/videos
|
||||||
|
pub hide_media: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, derive_new::new)]
|
#[derive(Clone, derive_new::new)]
|
||||||
|
@ -128,6 +130,8 @@ pub struct LocalUserInsertForm {
|
||||||
pub default_comment_sort_type: Option<CommentSortType>,
|
pub default_comment_sort_type: Option<CommentSortType>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
|
pub hide_media: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
@ -160,4 +164,5 @@ pub struct LocalUserUpdateForm {
|
||||||
pub collapse_bot_comments: Option<bool>,
|
pub collapse_bot_comments: Option<bool>,
|
||||||
pub default_comment_sort_type: Option<CommentSortType>,
|
pub default_comment_sort_type: Option<CommentSortType>,
|
||||||
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
||||||
|
pub hide_media: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ use diesel::{
|
||||||
OptionalExtension,
|
OptionalExtension,
|
||||||
PgTextExpressionMethods,
|
PgTextExpressionMethods,
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
|
TextExpressionMethods,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -320,6 +321,16 @@ fn queries<'a>() -> Queries<
|
||||||
query = query.filter(post_actions::hidden.is_null());
|
query = query.filter(post_actions::hidden.is_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.hide_media.unwrap_or(o.local_user.hide_media()) {
|
||||||
|
query = query.filter(not(
|
||||||
|
post::url_content_type.is_not_null().and(
|
||||||
|
post::url_content_type
|
||||||
|
.like("image/%")
|
||||||
|
.or(post::url_content_type.like("video/%")),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(my_id) = o.local_user.person_id() {
|
if let Some(my_id) = o.local_user.person_id() {
|
||||||
let not_creator_filter = post_aggregates::creator_id.ne(my_id);
|
let not_creator_filter = post_aggregates::creator_id.ne(my_id);
|
||||||
if o.liked_only.unwrap_or_default() {
|
if o.liked_only.unwrap_or_default() {
|
||||||
|
@ -518,6 +529,7 @@ pub struct PostQuery<'a> {
|
||||||
pub show_hidden: Option<bool>,
|
pub show_hidden: Option<bool>,
|
||||||
pub show_read: Option<bool>,
|
pub show_read: Option<bool>,
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
|
pub hide_media: Option<bool>,
|
||||||
pub no_comments_only: Option<bool>,
|
pub no_comments_only: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2192,6 +2204,66 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_context(Data)]
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
async fn post_listings_hide_media(data: &mut Data) -> LemmyResult<()> {
|
||||||
|
let pool = &data.pool();
|
||||||
|
let pool = &mut pool.into();
|
||||||
|
|
||||||
|
// Make one post an image post
|
||||||
|
Post::update(
|
||||||
|
pool,
|
||||||
|
data.inserted_bot_post.id,
|
||||||
|
&PostUpdateForm {
|
||||||
|
url_content_type: Some(Some(String::from("image/png"))),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Make sure all the posts are returned when `hide_media` is unset
|
||||||
|
let hide_media_listing = PostQuery {
|
||||||
|
community_id: Some(data.inserted_community.id),
|
||||||
|
local_user: Some(&data.local_user_view.local_user),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(&data.site, pool)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(3, hide_media_listing.len());
|
||||||
|
|
||||||
|
// Ensure the `hide_media` user setting is set
|
||||||
|
let local_user_form = LocalUserUpdateForm {
|
||||||
|
hide_media: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
LocalUser::update(pool, data.local_user_view.local_user.id, &local_user_form).await?;
|
||||||
|
data.local_user_view.local_user.hide_media = true;
|
||||||
|
|
||||||
|
// Ensure you don't see the image post
|
||||||
|
let hide_media_listing = PostQuery {
|
||||||
|
community_id: Some(data.inserted_community.id),
|
||||||
|
local_user: Some(&data.local_user_view.local_user),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(&data.site, pool)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(2, hide_media_listing.len());
|
||||||
|
|
||||||
|
// Make sure the `hide_media` override works
|
||||||
|
let hide_media_listing = PostQuery {
|
||||||
|
community_id: Some(data.inserted_community.id),
|
||||||
|
local_user: Some(&data.local_user_view.local_user),
|
||||||
|
hide_media: Some(false),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.list(&data.site, pool)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(3, hide_media_listing.len());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test_context(Data)]
|
#[test_context(Data)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
|
|
@ -243,6 +243,7 @@ mod tests {
|
||||||
enable_private_messages: inserted_sara_local_user.enable_private_messages,
|
enable_private_messages: inserted_sara_local_user.enable_private_messages,
|
||||||
collapse_bot_comments: inserted_sara_local_user.collapse_bot_comments,
|
collapse_bot_comments: inserted_sara_local_user.collapse_bot_comments,
|
||||||
auto_mark_fetched_posts_as_read: false,
|
auto_mark_fetched_posts_as_read: false,
|
||||||
|
hide_media: false,
|
||||||
},
|
},
|
||||||
creator: Person {
|
creator: Person {
|
||||||
id: inserted_sara_person.id,
|
id: inserted_sara_person.id,
|
||||||
|
|
5
migrations/2025-01-14-023145_media_filter/down.sql
Normal file
5
migrations/2025-01-14-023145_media_filter/down.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE local_user
|
||||||
|
DROP COLUMN hide_media;
|
||||||
|
|
||||||
|
DROP INDEX idx_post_url_content_type;
|
||||||
|
|
5
migrations/2025-01-14-023145_media_filter/up.sql
Normal file
5
migrations/2025-01-14-023145_media_filter/up.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE local_user
|
||||||
|
ADD COLUMN hide_media boolean DEFAULT FALSE NOT NULL;
|
||||||
|
|
||||||
|
CREATE INDEX idx_post_url_content_type ON post USING gin (url_content_type gin_trgm_ops);
|
||||||
|
|
Loading…
Reference in a new issue