]> Untitled Git - lemmy.git/blob - crates/api/src/site/search.rs
7c118a0b27885a76cd35a447759ae4374a1568ef
[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_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
38     let show_bot_accounts = local_user_view
39       .as_ref()
40       .map(|t| t.local_user.show_bot_accounts);
41     let show_read_posts = local_user_view
42       .as_ref()
43       .map(|t| t.local_user.show_read_posts);
44
45     let person_id = local_user_view.map(|u| u.person.id);
46
47     let mut posts = Vec::new();
48     let mut comments = Vec::new();
49     let mut communities = Vec::new();
50     let mut users = Vec::new();
51
52     // TODO no clean / non-nsfw searching rn
53
54     let q = data.q.to_owned();
55     let page = data.page;
56     let limit = data.limit;
57     let sort = data.sort;
58     let listing_type = data.listing_type;
59     let search_type = data.type_.unwrap_or(SearchType::All);
60     let community_id = data.community_id;
61     let community_actor_id = if let Some(name) = &data.community_name {
62       resolve_actor_identifier::<ApubCommunity, Community>(name, context)
63         .await
64         .ok()
65         .map(|c| c.actor_id)
66     } else {
67       None
68     };
69     let creator_id = data.creator_id;
70     match search_type {
71       SearchType::Posts => {
72         posts = blocking(context.pool(), move |conn| {
73           PostQuery::builder()
74             .conn(conn)
75             .sort(sort)
76             .show_nsfw(show_nsfw)
77             .show_bot_accounts(show_bot_accounts)
78             .show_read_posts(show_read_posts)
79             .listing_type(listing_type)
80             .community_id(community_id)
81             .community_actor_id(community_actor_id)
82             .creator_id(creator_id)
83             .my_person_id(person_id)
84             .search_term(Some(q))
85             .page(page)
86             .limit(limit)
87             .build()
88             .list()
89         })
90         .await??;
91       }
92       SearchType::Comments => {
93         comments = blocking(context.pool(), move |conn| {
94           CommentQuery::builder()
95             .conn(conn)
96             .sort(sort.map(post_to_comment_sort_type))
97             .listing_type(listing_type)
98             .search_term(Some(q))
99             .show_bot_accounts(show_bot_accounts)
100             .community_id(community_id)
101             .community_actor_id(community_actor_id)
102             .creator_id(creator_id)
103             .my_person_id(person_id)
104             .page(page)
105             .limit(limit)
106             .build()
107             .list()
108         })
109         .await??;
110       }
111       SearchType::Communities => {
112         communities = blocking(context.pool(), move |conn| {
113           CommunityQuery::builder()
114             .conn(conn)
115             .sort(sort)
116             .listing_type(listing_type)
117             .search_term(Some(q))
118             .my_person_id(person_id)
119             .page(page)
120             .limit(limit)
121             .build()
122             .list()
123         })
124         .await??;
125       }
126       SearchType::Users => {
127         users = blocking(context.pool(), move |conn| {
128           PersonQuery::builder()
129             .conn(conn)
130             .sort(sort)
131             .search_term(Some(q))
132             .page(page)
133             .limit(limit)
134             .build()
135             .list()
136         })
137         .await??;
138       }
139       SearchType::All => {
140         // If the community or creator is included, dont search communities or users
141         let community_or_creator_included =
142           data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
143         let community_actor_id_2 = community_actor_id.to_owned();
144
145         posts = blocking(context.pool(), move |conn| {
146           PostQuery::builder()
147             .conn(conn)
148             .sort(sort)
149             .show_nsfw(show_nsfw)
150             .show_bot_accounts(show_bot_accounts)
151             .show_read_posts(show_read_posts)
152             .listing_type(listing_type)
153             .community_id(community_id)
154             .community_actor_id(community_actor_id_2)
155             .creator_id(creator_id)
156             .my_person_id(person_id)
157             .search_term(Some(q))
158             .page(page)
159             .limit(limit)
160             .build()
161             .list()
162         })
163         .await??;
164
165         let q = data.q.to_owned();
166         let community_actor_id = community_actor_id.to_owned();
167
168         comments = blocking(context.pool(), move |conn| {
169           CommentQuery::builder()
170             .conn(conn)
171             .sort(sort.map(post_to_comment_sort_type))
172             .listing_type(listing_type)
173             .search_term(Some(q))
174             .show_bot_accounts(show_bot_accounts)
175             .community_id(community_id)
176             .community_actor_id(community_actor_id)
177             .creator_id(creator_id)
178             .my_person_id(person_id)
179             .page(page)
180             .limit(limit)
181             .build()
182             .list()
183         })
184         .await??;
185
186         let q = data.q.to_owned();
187
188         communities = if community_or_creator_included {
189           vec![]
190         } else {
191           blocking(context.pool(), move |conn| {
192             CommunityQuery::builder()
193               .conn(conn)
194               .sort(sort)
195               .listing_type(listing_type)
196               .search_term(Some(q))
197               .my_person_id(person_id)
198               .page(page)
199               .limit(limit)
200               .build()
201               .list()
202           })
203           .await??
204         };
205
206         let q = data.q.to_owned();
207
208         users = if community_or_creator_included {
209           vec![]
210         } else {
211           blocking(context.pool(), move |conn| {
212             PersonQuery::builder()
213               .conn(conn)
214               .sort(sort)
215               .search_term(Some(q))
216               .page(page)
217               .limit(limit)
218               .build()
219               .list()
220           })
221           .await??
222         };
223       }
224       SearchType::Url => {
225         posts = blocking(context.pool(), move |conn| {
226           PostQuery::builder()
227             .conn(conn)
228             .sort(sort)
229             .show_nsfw(show_nsfw)
230             .show_bot_accounts(show_bot_accounts)
231             .show_read_posts(show_read_posts)
232             .listing_type(listing_type)
233             .my_person_id(person_id)
234             .community_id(community_id)
235             .community_actor_id(community_actor_id)
236             .creator_id(creator_id)
237             .url_search(Some(q))
238             .page(page)
239             .limit(limit)
240             .build()
241             .list()
242         })
243         .await??;
244       }
245     };
246
247     // Blank out deleted or removed info for non logged in users
248     if person_id.is_none() {
249       for cv in communities
250         .iter_mut()
251         .filter(|cv| cv.community.deleted || cv.community.removed)
252       {
253         cv.community = cv.to_owned().community.blank_out_deleted_or_removed_info();
254       }
255
256       for pv in posts
257         .iter_mut()
258         .filter(|p| p.post.deleted || p.post.removed)
259       {
260         pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info();
261       }
262
263       for cv in comments
264         .iter_mut()
265         .filter(|cv| cv.comment.deleted || cv.comment.removed)
266       {
267         cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info();
268       }
269     }
270
271     // Return the jwt
272     Ok(SearchResponse {
273       type_: search_type.to_string(),
274       comments,
275       posts,
276       communities,
277       users,
278     })
279   }
280 }