Adding saved_only, liked_only, and disliked_only filters to search. (#5034)
* Adding saved_only, liked_only, and disliked_only filters to search. - Fixes #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.
This commit is contained in:
parent
a8843335a6
commit
62e1790ae7
7 changed files with 134 additions and 75 deletions
|
@ -79,6 +79,10 @@ pub struct Search {
|
|||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
pub post_title_only: Option<bool>,
|
||||
pub post_url_only: Option<bool>,
|
||||
pub saved_only: Option<bool>,
|
||||
pub liked_only: Option<bool>,
|
||||
pub disliked_only: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -989,6 +989,18 @@ fn limit_expire_time(expires: DateTime<Utc>) -> LemmyResult<Option<DateTime<Utc>
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn check_conflicting_like_filters(
|
||||
liked_only: Option<bool>,
|
||||
disliked_only: Option<bool>,
|
||||
) -> LemmyResult<()> {
|
||||
if liked_only.unwrap_or_default() && disliked_only.unwrap_or_default() {
|
||||
Err(LemmyErrorType::ContradictingFilters)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn process_markdown(
|
||||
text: &str,
|
||||
slur_regex: &Option<Regex>,
|
||||
|
|
|
@ -87,7 +87,8 @@ pub async fn get_post(
|
|||
// 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()),
|
||||
url_only: Some(true),
|
||||
search_term: Some(url.inner().as_str().into()),
|
||||
local_user: local_user.as_ref(),
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ use actix_web::web::{Json, Query};
|
|||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
post::{GetPosts, GetPostsResponse},
|
||||
utils::check_private_instance,
|
||||
utils::{check_conflicting_like_filters, check_private_instance},
|
||||
};
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_db_views::{
|
||||
post_view::PostQuery,
|
||||
structs::{LocalUserView, PaginationCursor, SiteView},
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_posts(
|
||||
|
@ -45,9 +45,7 @@ pub async fn list_posts(
|
|||
|
||||
let liked_only = data.liked_only;
|
||||
let disliked_only = data.disliked_only;
|
||||
if liked_only.unwrap_or_default() && disliked_only.unwrap_or_default() {
|
||||
return Err(LemmyError::from(LemmyErrorType::ContradictingFilters));
|
||||
}
|
||||
check_conflicting_like_filters(liked_only, disliked_only)?;
|
||||
|
||||
let local_user = local_user_view.as_ref().map(|u| &u.local_user);
|
||||
let listing_type = Some(listing_type_with_default(
|
||||
|
|
|
@ -4,7 +4,7 @@ use actix_web::web::{Json, Query};
|
|||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
site::{Search, SearchResponse},
|
||||
utils::{check_private_instance, is_admin},
|
||||
utils::{check_conflicting_like_filters, check_private_instance, is_admin},
|
||||
};
|
||||
use lemmy_db_schema::{source::community::Community, utils::post_to_comment_sort_type, SearchType};
|
||||
use lemmy_db_views::{
|
||||
|
@ -37,67 +37,87 @@ pub async fn search(
|
|||
|
||||
// TODO no clean / non-nsfw searching rn
|
||||
|
||||
let q = data.q.clone();
|
||||
let page = data.page;
|
||||
let limit = data.limit;
|
||||
let sort = data.sort;
|
||||
let listing_type = data.listing_type;
|
||||
let search_type = data.type_.unwrap_or(SearchType::All);
|
||||
let community_id = if let Some(name) = &data.community_name {
|
||||
let Query(Search {
|
||||
q,
|
||||
community_id,
|
||||
community_name,
|
||||
creator_id,
|
||||
type_,
|
||||
sort,
|
||||
listing_type,
|
||||
page,
|
||||
limit,
|
||||
post_title_only,
|
||||
post_url_only,
|
||||
saved_only,
|
||||
liked_only,
|
||||
disliked_only,
|
||||
}) = data;
|
||||
|
||||
let q = q.clone();
|
||||
let search_type = type_.unwrap_or(SearchType::All);
|
||||
let community_id = if let Some(name) = &community_name {
|
||||
Some(
|
||||
resolve_actor_identifier::<ApubCommunity, Community>(name, &context, &local_user_view, false)
|
||||
.await?,
|
||||
)
|
||||
.map(|c| c.id)
|
||||
} else {
|
||||
data.community_id
|
||||
community_id
|
||||
};
|
||||
let creator_id = data.creator_id;
|
||||
let local_user = local_user_view.as_ref().map(|l| &l.local_user);
|
||||
let post_title_only = data.post_title_only;
|
||||
|
||||
check_conflicting_like_filters(liked_only, disliked_only)?;
|
||||
|
||||
let posts_query = PostQuery {
|
||||
sort: (sort),
|
||||
listing_type: (listing_type),
|
||||
community_id: (community_id),
|
||||
creator_id: (creator_id),
|
||||
sort,
|
||||
listing_type,
|
||||
community_id,
|
||||
creator_id,
|
||||
local_user,
|
||||
search_term: (Some(q.clone())),
|
||||
page: (page),
|
||||
limit: (limit),
|
||||
title_only: (post_title_only),
|
||||
search_term: Some(q.clone()),
|
||||
page,
|
||||
limit,
|
||||
title_only: post_title_only,
|
||||
url_only: post_url_only,
|
||||
liked_only,
|
||||
disliked_only,
|
||||
saved_only,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let comment_query = CommentQuery {
|
||||
sort: (sort.map(post_to_comment_sort_type)),
|
||||
listing_type: (listing_type),
|
||||
search_term: (Some(q.clone())),
|
||||
community_id: (community_id),
|
||||
creator_id: (creator_id),
|
||||
sort: sort.map(post_to_comment_sort_type),
|
||||
listing_type,
|
||||
search_term: Some(q.clone()),
|
||||
community_id,
|
||||
creator_id,
|
||||
local_user,
|
||||
page: (page),
|
||||
limit: (limit),
|
||||
page,
|
||||
limit,
|
||||
liked_only,
|
||||
disliked_only,
|
||||
saved_only,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let community_query = CommunityQuery {
|
||||
sort: (sort),
|
||||
listing_type: (listing_type),
|
||||
search_term: (Some(q.clone())),
|
||||
sort,
|
||||
listing_type,
|
||||
search_term: Some(q.clone()),
|
||||
local_user,
|
||||
is_mod_or_admin: (is_admin),
|
||||
page: (page),
|
||||
limit: (limit),
|
||||
is_mod_or_admin: is_admin,
|
||||
page,
|
||||
limit,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let person_query = PersonQuery {
|
||||
sort,
|
||||
search_term: (Some(q.clone())),
|
||||
listing_type: (listing_type),
|
||||
page: (page),
|
||||
limit: (limit),
|
||||
search_term: Some(q.clone()),
|
||||
listing_type,
|
||||
page,
|
||||
limit,
|
||||
};
|
||||
|
||||
match search_type {
|
||||
|
@ -120,7 +140,7 @@ pub async fn search(
|
|||
SearchType::All => {
|
||||
// If the community or creator is included, dont search communities or users
|
||||
let community_or_creator_included =
|
||||
data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
|
||||
community_id.is_some() || community_name.is_some() || creator_id.is_some();
|
||||
|
||||
posts = posts_query
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
|
@ -142,21 +162,6 @@ pub async fn search(
|
|||
person_query.list(&mut context.pool()).await?
|
||||
};
|
||||
}
|
||||
SearchType::Url => {
|
||||
posts = PostQuery {
|
||||
sort: (sort),
|
||||
listing_type: (listing_type),
|
||||
community_id: (community_id),
|
||||
creator_id: (creator_id),
|
||||
url_search: (Some(q)),
|
||||
local_user,
|
||||
page: (page),
|
||||
limit: (limit),
|
||||
..Default::default()
|
||||
}
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
.await?;
|
||||
}
|
||||
};
|
||||
|
||||
// Return the jwt
|
||||
|
|
|
@ -182,7 +182,6 @@ pub enum SearchType {
|
|||
Posts,
|
||||
Communities,
|
||||
Users,
|
||||
Url,
|
||||
}
|
||||
|
||||
#[derive(EnumString, Display, Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Hash)]
|
||||
|
|
|
@ -382,11 +382,10 @@ fn queries<'a>() -> Queries<
|
|||
query = query.filter(community::hidden.eq(false));
|
||||
}
|
||||
|
||||
if let Some(url_search) = &options.url_search {
|
||||
query = query.filter(post::url.eq(url_search));
|
||||
}
|
||||
|
||||
if let Some(search_term) = &options.search_term {
|
||||
if options.url_only.unwrap_or_default() {
|
||||
query = query.filter(post::url.eq(search_term));
|
||||
} else {
|
||||
let searcher = fuzzy_search(search_term);
|
||||
query = if options.title_only.unwrap_or_default() {
|
||||
query.filter(post::name.ilike(searcher))
|
||||
|
@ -399,6 +398,7 @@ fn queries<'a>() -> Queries<
|
|||
}
|
||||
.filter(not(post::removed.or(post::deleted)));
|
||||
}
|
||||
}
|
||||
|
||||
if !options
|
||||
.show_nsfw
|
||||
|
@ -616,7 +616,7 @@ pub struct PostQuery<'a> {
|
|||
pub community_id_just_for_prefetch: bool,
|
||||
pub local_user: Option<&'a LocalUser>,
|
||||
pub search_term: Option<String>,
|
||||
pub url_search: Option<String>,
|
||||
pub url_only: Option<bool>,
|
||||
pub saved_only: Option<bool>,
|
||||
pub liked_only: Option<bool>,
|
||||
pub disliked_only: Option<bool>,
|
||||
|
@ -765,10 +765,20 @@ mod tests {
|
|||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
post::{Post, PostHide, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
||||
post::{
|
||||
Post,
|
||||
PostHide,
|
||||
PostInsertForm,
|
||||
PostLike,
|
||||
PostLikeForm,
|
||||
PostRead,
|
||||
PostSaved,
|
||||
PostSavedForm,
|
||||
PostUpdateForm,
|
||||
},
|
||||
site::Site,
|
||||
},
|
||||
traits::{Bannable, Blockable, Crud, Joinable, Likeable},
|
||||
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
|
||||
utils::{build_db_pool, build_db_pool_for_tests, DbPool, RANK_DEFAULT},
|
||||
CommunityVisibility,
|
||||
PostSortType,
|
||||
|
@ -1215,6 +1225,36 @@ mod tests {
|
|||
cleanup(data, pool).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn post_listing_saved_only() -> LemmyResult<()> {
|
||||
let pool = &build_db_pool().await?;
|
||||
let pool = &mut pool.into();
|
||||
let data = init_data(pool).await?;
|
||||
|
||||
// Save only the bot post
|
||||
// The saved_only should only show the bot post
|
||||
let post_save_form = PostSavedForm {
|
||||
post_id: data.inserted_bot_post.id,
|
||||
person_id: data.local_user_view.person.id,
|
||||
};
|
||||
PostSaved::save(pool, &post_save_form).await?;
|
||||
|
||||
// Read the saved only
|
||||
let read_saved_post_listing = PostQuery {
|
||||
community_id: Some(data.inserted_community.id),
|
||||
saved_only: Some(true),
|
||||
..data.default_post_query()
|
||||
}
|
||||
.list(&data.site, pool)
|
||||
.await?;
|
||||
|
||||
// This should only include the bot post, not the one you created
|
||||
assert_eq!(vec![POST_BY_BOT], names(&read_saved_post_listing));
|
||||
|
||||
cleanup(data, pool).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn creator_info() -> LemmyResult<()> {
|
||||
|
|
Loading…
Reference in a new issue