2 use actix_web::web::Data;
3 use lemmy_api_common::{
5 check_private_instance,
6 get_local_user_view_from_jwt_opt,
7 site::{Search, SearchResponse},
9 use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
10 use lemmy_db_schema::{
11 from_opt_str_to_opt_enum,
12 source::community::Community,
13 traits::DeleteableOrRemoveable,
18 use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
19 use lemmy_db_views_actor::{
20 community_view::CommunityQueryBuilder,
21 person_view::PersonQueryBuilder,
23 use lemmy_utils::{ConnectionId, LemmyError};
24 use lemmy_websocket::LemmyContext;
26 #[async_trait::async_trait(?Send)]
27 impl Perform for Search {
28 type Response = SearchResponse;
30 #[tracing::instrument(skip(context, _websocket_id))]
33 context: &Data<LemmyContext>,
34 _websocket_id: Option<ConnectionId>,
35 ) -> Result<SearchResponse, LemmyError> {
36 let data: &Search = self;
39 get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
42 check_private_instance(&local_user_view, context.pool()).await?;
44 let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
45 let show_bot_accounts = local_user_view
47 .map(|t| t.local_user.show_bot_accounts);
48 let show_read_posts = local_user_view
50 .map(|t| t.local_user.show_read_posts);
52 let person_id = local_user_view.map(|u| u.person.id);
54 let mut posts = Vec::new();
55 let mut comments = Vec::new();
56 let mut communities = Vec::new();
57 let mut users = Vec::new();
59 // TODO no clean / non-nsfw searching rn
61 let q = data.q.to_owned();
63 let limit = data.limit;
64 let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
65 let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.listing_type);
66 let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All);
67 let community_id = data.community_id;
68 let community_actor_id = if let Some(name) = &data.community_name {
69 resolve_actor_identifier::<ApubCommunity, Community>(name, context)
76 let creator_id = data.creator_id;
78 SearchType::Posts => {
79 posts = blocking(context.pool(), move |conn| {
80 PostQueryBuilder::create(conn)
83 .show_bot_accounts(show_bot_accounts)
84 .show_read_posts(show_read_posts)
85 .listing_type(listing_type)
86 .community_id(community_id)
87 .community_actor_id(community_actor_id)
88 .creator_id(creator_id)
89 .my_person_id(person_id)
97 SearchType::Comments => {
98 comments = blocking(context.pool(), move |conn| {
99 CommentQueryBuilder::create(conn)
101 .listing_type(listing_type)
103 .show_bot_accounts(show_bot_accounts)
104 .community_id(community_id)
105 .community_actor_id(community_actor_id)
106 .creator_id(creator_id)
107 .my_person_id(person_id)
114 SearchType::Communities => {
115 communities = blocking(context.pool(), move |conn| {
116 CommunityQueryBuilder::create(conn)
118 .listing_type(listing_type)
120 .my_person_id(person_id)
127 SearchType::Users => {
128 users = blocking(context.pool(), move |conn| {
129 PersonQueryBuilder::create(conn)
139 // If the community or creator is included, dont search communities or users
140 let community_or_creator_included =
141 data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
142 let community_actor_id_2 = community_actor_id.to_owned();
144 posts = blocking(context.pool(), move |conn| {
145 PostQueryBuilder::create(conn)
147 .show_nsfw(show_nsfw)
148 .show_bot_accounts(show_bot_accounts)
149 .show_read_posts(show_read_posts)
150 .listing_type(listing_type)
151 .community_id(community_id)
152 .community_actor_id(community_actor_id_2)
153 .creator_id(creator_id)
154 .my_person_id(person_id)
162 let q = data.q.to_owned();
163 let community_actor_id = community_actor_id.to_owned();
165 comments = blocking(context.pool(), move |conn| {
166 CommentQueryBuilder::create(conn)
168 .listing_type(listing_type)
170 .show_bot_accounts(show_bot_accounts)
171 .community_id(community_id)
172 .community_actor_id(community_actor_id)
173 .creator_id(creator_id)
174 .my_person_id(person_id)
181 let q = data.q.to_owned();
183 communities = if community_or_creator_included {
186 blocking(context.pool(), move |conn| {
187 CommunityQueryBuilder::create(conn)
189 .listing_type(listing_type)
191 .my_person_id(person_id)
199 let q = data.q.to_owned();
201 users = if community_or_creator_included {
204 blocking(context.pool(), move |conn| {
205 PersonQueryBuilder::create(conn)
216 posts = blocking(context.pool(), move |conn| {
217 PostQueryBuilder::create(conn)
219 .show_nsfw(show_nsfw)
220 .show_bot_accounts(show_bot_accounts)
221 .show_read_posts(show_read_posts)
222 .listing_type(listing_type)
223 .my_person_id(person_id)
224 .community_id(community_id)
225 .community_actor_id(community_actor_id)
226 .creator_id(creator_id)
236 // Blank out deleted or removed info for non logged in users
237 if person_id.is_none() {
238 for cv in communities
240 .filter(|cv| cv.community.deleted || cv.community.removed)
242 cv.community = cv.to_owned().community.blank_out_deleted_or_removed_info();
247 .filter(|p| p.post.deleted || p.post.removed)
249 pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info();
254 .filter(|cv| cv.comment.deleted || cv.comment.removed)
256 cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info();
262 type_: search_type.to_string(),