Skip to content

Commit 62e1790

Browse files
authored
Adding saved_only, liked_only, and disliked_only filters to search. (LemmyNet#5034)
* Adding saved_only, liked_only, and disliked_only filters to search. - Fixes LemmyNet#4547 * Removing duplicate Url return type for search (was actually post). - This now works like the post_title_only filter. * Address PR comments. * Add saved_only post_view test.
1 parent a884333 commit 62e1790

File tree

7 files changed

+134
-75
lines changed

7 files changed

+134
-75
lines changed

crates/api_common/src/site.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ pub struct Search {
7979
pub page: Option<i64>,
8080
pub limit: Option<i64>,
8181
pub post_title_only: Option<bool>,
82+
pub post_url_only: Option<bool>,
83+
pub saved_only: Option<bool>,
84+
pub liked_only: Option<bool>,
85+
pub disliked_only: Option<bool>,
8286
}
8387

8488
#[derive(Debug, Serialize, Deserialize, Clone)]

crates/api_common/src/utils.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,18 @@ fn limit_expire_time(expires: DateTime<Utc>) -> LemmyResult<Option<DateTime<Utc>
989989
}
990990
}
991991

992+
#[tracing::instrument(skip_all)]
993+
pub fn check_conflicting_like_filters(
994+
liked_only: Option<bool>,
995+
disliked_only: Option<bool>,
996+
) -> LemmyResult<()> {
997+
if liked_only.unwrap_or_default() && disliked_only.unwrap_or_default() {
998+
Err(LemmyErrorType::ContradictingFilters)?
999+
} else {
1000+
Ok(())
1001+
}
1002+
}
1003+
9921004
pub async fn process_markdown(
9931005
text: &str,
9941006
slur_regex: &Option<Regex>,

crates/api_crud/src/post/read.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ pub async fn get_post(
8787
// Fetch the cross_posts
8888
let cross_posts = if let Some(url) = &post_view.post.url {
8989
let mut x_posts = PostQuery {
90-
url_search: Some(url.inner().as_str().into()),
90+
url_only: Some(true),
91+
search_term: Some(url.inner().as_str().into()),
9192
local_user: local_user.as_ref(),
9293
..Default::default()
9394
}

crates/apub/src/api/list_posts.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use actix_web::web::{Json, Query};
88
use lemmy_api_common::{
99
context::LemmyContext,
1010
post::{GetPosts, GetPostsResponse},
11-
utils::check_private_instance,
11+
utils::{check_conflicting_like_filters, check_private_instance},
1212
};
1313
use lemmy_db_schema::source::community::Community;
1414
use lemmy_db_views::{
1515
post_view::PostQuery,
1616
structs::{LocalUserView, PaginationCursor, SiteView},
1717
};
18-
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
18+
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
1919

2020
#[tracing::instrument(skip(context))]
2121
pub async fn list_posts(
@@ -45,9 +45,7 @@ pub async fn list_posts(
4545

4646
let liked_only = data.liked_only;
4747
let disliked_only = data.disliked_only;
48-
if liked_only.unwrap_or_default() && disliked_only.unwrap_or_default() {
49-
return Err(LemmyError::from(LemmyErrorType::ContradictingFilters));
50-
}
48+
check_conflicting_like_filters(liked_only, disliked_only)?;
5149

5250
let local_user = local_user_view.as_ref().map(|u| &u.local_user);
5351
let listing_type = Some(listing_type_with_default(

crates/apub/src/api/search.rs

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use actix_web::web::{Json, Query};
44
use lemmy_api_common::{
55
context::LemmyContext,
66
site::{Search, SearchResponse},
7-
utils::{check_private_instance, is_admin},
7+
utils::{check_conflicting_like_filters, check_private_instance, is_admin},
88
};
99
use lemmy_db_schema::{source::community::Community, utils::post_to_comment_sort_type, SearchType};
1010
use lemmy_db_views::{
@@ -37,67 +37,87 @@ pub async fn search(
3737

3838
// TODO no clean / non-nsfw searching rn
3939

40-
let q = data.q.clone();
41-
let page = data.page;
42-
let limit = data.limit;
43-
let sort = data.sort;
44-
let listing_type = data.listing_type;
45-
let search_type = data.type_.unwrap_or(SearchType::All);
46-
let community_id = if let Some(name) = &data.community_name {
40+
let Query(Search {
41+
q,
42+
community_id,
43+
community_name,
44+
creator_id,
45+
type_,
46+
sort,
47+
listing_type,
48+
page,
49+
limit,
50+
post_title_only,
51+
post_url_only,
52+
saved_only,
53+
liked_only,
54+
disliked_only,
55+
}) = data;
56+
57+
let q = q.clone();
58+
let search_type = type_.unwrap_or(SearchType::All);
59+
let community_id = if let Some(name) = &community_name {
4760
Some(
4861
resolve_actor_identifier::<ApubCommunity, Community>(name, &context, &local_user_view, false)
4962
.await?,
5063
)
5164
.map(|c| c.id)
5265
} else {
53-
data.community_id
66+
community_id
5467
};
55-
let creator_id = data.creator_id;
5668
let local_user = local_user_view.as_ref().map(|l| &l.local_user);
57-
let post_title_only = data.post_title_only;
69+
70+
check_conflicting_like_filters(liked_only, disliked_only)?;
5871

5972
let posts_query = PostQuery {
60-
sort: (sort),
61-
listing_type: (listing_type),
62-
community_id: (community_id),
63-
creator_id: (creator_id),
73+
sort,
74+
listing_type,
75+
community_id,
76+
creator_id,
6477
local_user,
65-
search_term: (Some(q.clone())),
66-
page: (page),
67-
limit: (limit),
68-
title_only: (post_title_only),
78+
search_term: Some(q.clone()),
79+
page,
80+
limit,
81+
title_only: post_title_only,
82+
url_only: post_url_only,
83+
liked_only,
84+
disliked_only,
85+
saved_only,
6986
..Default::default()
7087
};
7188

7289
let comment_query = CommentQuery {
73-
sort: (sort.map(post_to_comment_sort_type)),
74-
listing_type: (listing_type),
75-
search_term: (Some(q.clone())),
76-
community_id: (community_id),
77-
creator_id: (creator_id),
90+
sort: sort.map(post_to_comment_sort_type),
91+
listing_type,
92+
search_term: Some(q.clone()),
93+
community_id,
94+
creator_id,
7895
local_user,
79-
page: (page),
80-
limit: (limit),
96+
page,
97+
limit,
98+
liked_only,
99+
disliked_only,
100+
saved_only,
81101
..Default::default()
82102
};
83103

84104
let community_query = CommunityQuery {
85-
sort: (sort),
86-
listing_type: (listing_type),
87-
search_term: (Some(q.clone())),
105+
sort,
106+
listing_type,
107+
search_term: Some(q.clone()),
88108
local_user,
89-
is_mod_or_admin: (is_admin),
90-
page: (page),
91-
limit: (limit),
109+
is_mod_or_admin: is_admin,
110+
page,
111+
limit,
92112
..Default::default()
93113
};
94114

95115
let person_query = PersonQuery {
96116
sort,
97-
search_term: (Some(q.clone())),
98-
listing_type: (listing_type),
99-
page: (page),
100-
limit: (limit),
117+
search_term: Some(q.clone()),
118+
listing_type,
119+
page,
120+
limit,
101121
};
102122

103123
match search_type {
@@ -120,7 +140,7 @@ pub async fn search(
120140
SearchType::All => {
121141
// If the community or creator is included, dont search communities or users
122142
let community_or_creator_included =
123-
data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
143+
community_id.is_some() || community_name.is_some() || creator_id.is_some();
124144

125145
posts = posts_query
126146
.list(&local_site.site, &mut context.pool())
@@ -142,21 +162,6 @@ pub async fn search(
142162
person_query.list(&mut context.pool()).await?
143163
};
144164
}
145-
SearchType::Url => {
146-
posts = PostQuery {
147-
sort: (sort),
148-
listing_type: (listing_type),
149-
community_id: (community_id),
150-
creator_id: (creator_id),
151-
url_search: (Some(q)),
152-
local_user,
153-
page: (page),
154-
limit: (limit),
155-
..Default::default()
156-
}
157-
.list(&local_site.site, &mut context.pool())
158-
.await?;
159-
}
160165
};
161166

162167
// Return the jwt

crates/db_schema/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ pub enum SearchType {
182182
Posts,
183183
Communities,
184184
Users,
185-
Url,
186185
}
187186

188187
#[derive(EnumString, Display, Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Hash)]

crates/db_views/src/post_view.rs

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -382,22 +382,22 @@ fn queries<'a>() -> Queries<
382382
query = query.filter(community::hidden.eq(false));
383383
}
384384

385-
if let Some(url_search) = &options.url_search {
386-
query = query.filter(post::url.eq(url_search));
387-
}
388-
389385
if let Some(search_term) = &options.search_term {
390-
let searcher = fuzzy_search(search_term);
391-
query = if options.title_only.unwrap_or_default() {
392-
query.filter(post::name.ilike(searcher))
386+
if options.url_only.unwrap_or_default() {
387+
query = query.filter(post::url.eq(search_term));
393388
} else {
394-
query.filter(
395-
post::name
396-
.ilike(searcher.clone())
397-
.or(post::body.ilike(searcher)),
398-
)
389+
let searcher = fuzzy_search(search_term);
390+
query = if options.title_only.unwrap_or_default() {
391+
query.filter(post::name.ilike(searcher))
392+
} else {
393+
query.filter(
394+
post::name
395+
.ilike(searcher.clone())
396+
.or(post::body.ilike(searcher)),
397+
)
398+
}
399+
.filter(not(post::removed.or(post::deleted)));
399400
}
400-
.filter(not(post::removed.or(post::deleted)));
401401
}
402402

403403
if !options
@@ -616,7 +616,7 @@ pub struct PostQuery<'a> {
616616
pub community_id_just_for_prefetch: bool,
617617
pub local_user: Option<&'a LocalUser>,
618618
pub search_term: Option<String>,
619-
pub url_search: Option<String>,
619+
pub url_only: Option<bool>,
620620
pub saved_only: Option<bool>,
621621
pub liked_only: Option<bool>,
622622
pub disliked_only: Option<bool>,
@@ -765,10 +765,20 @@ mod tests {
765765
local_user_vote_display_mode::LocalUserVoteDisplayMode,
766766
person::{Person, PersonInsertForm},
767767
person_block::{PersonBlock, PersonBlockForm},
768-
post::{Post, PostHide, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
768+
post::{
769+
Post,
770+
PostHide,
771+
PostInsertForm,
772+
PostLike,
773+
PostLikeForm,
774+
PostRead,
775+
PostSaved,
776+
PostSavedForm,
777+
PostUpdateForm,
778+
},
769779
site::Site,
770780
},
771-
traits::{Bannable, Blockable, Crud, Joinable, Likeable},
781+
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
772782
utils::{build_db_pool, build_db_pool_for_tests, DbPool, RANK_DEFAULT},
773783
CommunityVisibility,
774784
PostSortType,
@@ -1215,6 +1225,36 @@ mod tests {
12151225
cleanup(data, pool).await
12161226
}
12171227

1228+
#[tokio::test]
1229+
#[serial]
1230+
async fn post_listing_saved_only() -> LemmyResult<()> {
1231+
let pool = &build_db_pool().await?;
1232+
let pool = &mut pool.into();
1233+
let data = init_data(pool).await?;
1234+
1235+
// Save only the bot post
1236+
// The saved_only should only show the bot post
1237+
let post_save_form = PostSavedForm {
1238+
post_id: data.inserted_bot_post.id,
1239+
person_id: data.local_user_view.person.id,
1240+
};
1241+
PostSaved::save(pool, &post_save_form).await?;
1242+
1243+
// Read the saved only
1244+
let read_saved_post_listing = PostQuery {
1245+
community_id: Some(data.inserted_community.id),
1246+
saved_only: Some(true),
1247+
..data.default_post_query()
1248+
}
1249+
.list(&data.site, pool)
1250+
.await?;
1251+
1252+
// This should only include the bot post, not the one you created
1253+
assert_eq!(vec![POST_BY_BOT], names(&read_saved_post_listing));
1254+
1255+
cleanup(data, pool).await
1256+
}
1257+
12181258
#[tokio::test]
12191259
#[serial]
12201260
async fn creator_info() -> LemmyResult<()> {

0 commit comments

Comments
 (0)