]> Untitled Git - lemmy.git/blob - crates/api/src/site/search.rs
bd04b053c2077b6af96ae5cc5a7b27e41e491cbb
[lemmy.git] / crates / api / src / site / search.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   site::{Search, SearchResponse},
5   utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
6 };
7 use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
8 use lemmy_db_schema::{
9   source::community::Community,
10   traits::DeleteableOrRemoveable,
11   utils::post_to_comment_sort_type,
12   SearchType,
13 };
14 use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
15 use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery};
16 use lemmy_utils::{error::LemmyError, ConnectionId};
17 use lemmy_websocket::LemmyContext;
18
19 #[async_trait::async_trait(?Send)]
20 impl Perform for Search {
21   type Response = SearchResponse;
22
23   #[tracing::instrument(skip(context, _websocket_id))]
24   async fn perform(
25     &self,
26     context: &Data<LemmyContext>,
27     _websocket_id: Option<ConnectionId>,
28   ) -> Result<SearchResponse, LemmyError> {
29     let data: &Search = self;
30
31     let local_user_view =
32       get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
33         .await?;
34
35     check_private_instance(&local_user_view, context.pool()).await?;
36
37     let show_bot_accounts = local_user_view
38       .as_ref()
39       .map(|t| t.local_user.show_bot_accounts);
40
41     let person_id = local_user_view.as_ref().map(|u| u.person.id);
42
43     let mut posts = Vec::new();
44     let mut comments = Vec::new();
45     let mut communities = Vec::new();
46     let mut users = Vec::new();
47
48     // TODO no clean / non-nsfw searching rn
49
50     let q = data.q.to_owned();
51     let page = data.page;
52     let limit = data.limit;
53     let sort = data.sort;
54     let listing_type = data.listing_type;
55     let search_type = data.type_.unwrap_or(SearchType::All);
56     let community_id = data.community_id;
57     let community_actor_id = if let Some(name) = &data.community_name {
58       resolve_actor_identifier::<ApubCommunity, Community>(name, context)
59         .await
60         .ok()
61         .map(|c| c.actor_id)
62     } else {
63       None
64     };
65     let creator_id = data.creator_id;
66     match search_type {
67       SearchType::Posts => {
68         posts = blocking(context.pool(), move |conn| {
69           PostQuery::builder()
70             .conn(conn)
71             .sort(sort)
72             .listing_type(listing_type)
73             .community_id(community_id)
74             .community_actor_id(community_actor_id)
75             .creator_id(creator_id)
76             .my_person_id(person_id)
77             .search_term(Some(q))
78             .page(page)
79             .limit(limit)
80             .build()
81             .list()
82         })
83         .await??;
84       }
85       SearchType::Comments => {
86         comments = blocking(context.pool(), move |conn| {
87           CommentQuery::builder()
88             .conn(conn)
89             .sort(sort.map(post_to_comment_sort_type))
90             .listing_type(listing_type)
91             .search_term(Some(q))
92             .show_bot_accounts(show_bot_accounts)
93             .community_id(community_id)
94             .community_actor_id(community_actor_id)
95             .creator_id(creator_id)
96             .my_person_id(person_id)
97             .page(page)
98             .limit(limit)
99             .build()
100             .list()
101         })
102         .await??;
103       }
104       SearchType::Communities => {
105         communities = blocking(context.pool(), move |conn| {
106           CommunityQuery::builder()
107             .conn(conn)
108             .sort(sort)
109             .listing_type(listing_type)
110             .search_term(Some(q))
111             .my_person_id(person_id)
112             .page(page)
113             .limit(limit)
114             .build()
115             .list()
116         })
117         .await??;
118       }
119       SearchType::Users => {
120         users = blocking(context.pool(), move |conn| {
121           PersonQuery::builder()
122             .conn(conn)
123             .sort(sort)
124             .search_term(Some(q))
125             .page(page)
126             .limit(limit)
127             .build()
128             .list()
129         })
130         .await??;
131       }
132       SearchType::All => {
133         // If the community or creator is included, dont search communities or users
134         let community_or_creator_included =
135           data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
136         let community_actor_id_2 = community_actor_id.to_owned();
137
138         posts = blocking(context.pool(), move |conn| {
139           PostQuery::builder()
140             .conn(conn)
141             .sort(sort)
142             .listing_type(listing_type)
143             .community_id(community_id)
144             .community_actor_id(community_actor_id_2)
145             .creator_id(creator_id)
146             .my_person_id(person_id)
147             .search_term(Some(q))
148             .page(page)
149             .limit(limit)
150             .build()
151             .list()
152         })
153         .await??;
154
155         let q = data.q.to_owned();
156         let community_actor_id = community_actor_id.to_owned();
157
158         comments = blocking(context.pool(), move |conn| {
159           CommentQuery::builder()
160             .conn(conn)
161             .sort(sort.map(post_to_comment_sort_type))
162             .listing_type(listing_type)
163             .search_term(Some(q))
164             .show_bot_accounts(show_bot_accounts)
165             .community_id(community_id)
166             .community_actor_id(community_actor_id)
167             .creator_id(creator_id)
168             .my_person_id(person_id)
169             .page(page)
170             .limit(limit)
171             .build()
172             .list()
173         })
174         .await??;
175
176         let q = data.q.to_owned();
177
178         communities = if community_or_creator_included {
179           vec![]
180         } else {
181           blocking(context.pool(), move |conn| {
182             CommunityQuery::builder()
183               .conn(conn)
184               .sort(sort)
185               .listing_type(listing_type)
186               .search_term(Some(q))
187               .my_person_id(person_id)
188               .page(page)
189               .limit(limit)
190               .build()
191               .list()
192           })
193           .await??
194         };
195
196         let q = data.q.to_owned();
197
198         users = if community_or_creator_included {
199           vec![]
200         } else {
201           blocking(context.pool(), move |conn| {
202             PersonQuery::builder()
203               .conn(conn)
204               .sort(sort)
205               .search_term(Some(q))
206               .page(page)
207               .limit(limit)
208               .build()
209               .list()
210           })
211           .await??
212         };
213       }
214       SearchType::Url => {
215         posts = blocking(context.pool(), move |conn| {
216           PostQuery::builder()
217             .conn(conn)
218             .sort(sort)
219             .listing_type(listing_type)
220             .community_id(community_id)
221             .community_actor_id(community_actor_id)
222             .creator_id(creator_id)
223             .url_search(Some(q))
224             .page(page)
225             .limit(limit)
226             .build()
227             .list()
228         })
229         .await??;
230       }
231     };
232
233     // Blank out deleted or removed info for non logged in users
234     if person_id.is_none() {
235       for cv in communities
236         .iter_mut()
237         .filter(|cv| cv.community.deleted || cv.community.removed)
238       {
239         cv.community = cv.to_owned().community.blank_out_deleted_or_removed_info();
240       }
241
242       for pv in posts
243         .iter_mut()
244         .filter(|p| p.post.deleted || p.post.removed)
245       {
246         pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info();
247       }
248
249       for cv in comments
250         .iter_mut()
251         .filter(|cv| cv.comment.deleted || cv.comment.removed)
252       {
253         cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info();
254       }
255     }
256
257     // Return the jwt
258     Ok(SearchResponse {
259       type_: search_type.to_string(),
260       comments,
261       posts,
262       communities,
263       users,
264     })
265   }
266 }