]> Untitled Git - lemmy.git/blob - crates/api/src/site/search.rs
Split apart api files (#2216)
[lemmy.git] / crates / api / src / site / search.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   check_private_instance,
6   get_local_user_view_from_jwt_opt,
7   site::{Search, SearchResponse},
8 };
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,
14   ListingType,
15   SearchType,
16   SortType,
17 };
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,
22 };
23 use lemmy_utils::{ConnectionId, LemmyError};
24 use lemmy_websocket::LemmyContext;
25
26 #[async_trait::async_trait(?Send)]
27 impl Perform for Search {
28   type Response = SearchResponse;
29
30   #[tracing::instrument(skip(context, _websocket_id))]
31   async fn perform(
32     &self,
33     context: &Data<LemmyContext>,
34     _websocket_id: Option<ConnectionId>,
35   ) -> Result<SearchResponse, LemmyError> {
36     let data: &Search = self;
37
38     let local_user_view =
39       get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
40         .await?;
41
42     check_private_instance(&local_user_view, context.pool()).await?;
43
44     let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
45     let show_bot_accounts = local_user_view
46       .as_ref()
47       .map(|t| t.local_user.show_bot_accounts);
48     let show_read_posts = local_user_view
49       .as_ref()
50       .map(|t| t.local_user.show_read_posts);
51
52     let person_id = local_user_view.map(|u| u.person.id);
53
54     let mut posts = Vec::new();
55     let mut comments = Vec::new();
56     let mut communities = Vec::new();
57     let mut users = Vec::new();
58
59     // TODO no clean / non-nsfw searching rn
60
61     let q = data.q.to_owned();
62     let page = data.page;
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)
70         .await
71         .ok()
72         .map(|c| c.actor_id)
73     } else {
74       None
75     };
76     let creator_id = data.creator_id;
77     match search_type {
78       SearchType::Posts => {
79         posts = blocking(context.pool(), move |conn| {
80           PostQueryBuilder::create(conn)
81             .sort(sort)
82             .show_nsfw(show_nsfw)
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)
90             .search_term(q)
91             .page(page)
92             .limit(limit)
93             .list()
94         })
95         .await??;
96       }
97       SearchType::Comments => {
98         comments = blocking(context.pool(), move |conn| {
99           CommentQueryBuilder::create(conn)
100             .sort(sort)
101             .listing_type(listing_type)
102             .search_term(q)
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)
108             .page(page)
109             .limit(limit)
110             .list()
111         })
112         .await??;
113       }
114       SearchType::Communities => {
115         communities = blocking(context.pool(), move |conn| {
116           CommunityQueryBuilder::create(conn)
117             .sort(sort)
118             .listing_type(listing_type)
119             .search_term(q)
120             .my_person_id(person_id)
121             .page(page)
122             .limit(limit)
123             .list()
124         })
125         .await??;
126       }
127       SearchType::Users => {
128         users = blocking(context.pool(), move |conn| {
129           PersonQueryBuilder::create(conn)
130             .sort(sort)
131             .search_term(q)
132             .page(page)
133             .limit(limit)
134             .list()
135         })
136         .await??;
137       }
138       SearchType::All => {
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();
143
144         posts = blocking(context.pool(), move |conn| {
145           PostQueryBuilder::create(conn)
146             .sort(sort)
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)
155             .search_term(q)
156             .page(page)
157             .limit(limit)
158             .list()
159         })
160         .await??;
161
162         let q = data.q.to_owned();
163         let community_actor_id = community_actor_id.to_owned();
164
165         comments = blocking(context.pool(), move |conn| {
166           CommentQueryBuilder::create(conn)
167             .sort(sort)
168             .listing_type(listing_type)
169             .search_term(q)
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)
175             .page(page)
176             .limit(limit)
177             .list()
178         })
179         .await??;
180
181         let q = data.q.to_owned();
182
183         communities = if community_or_creator_included {
184           vec![]
185         } else {
186           blocking(context.pool(), move |conn| {
187             CommunityQueryBuilder::create(conn)
188               .sort(sort)
189               .listing_type(listing_type)
190               .search_term(q)
191               .my_person_id(person_id)
192               .page(page)
193               .limit(limit)
194               .list()
195           })
196           .await??
197         };
198
199         let q = data.q.to_owned();
200
201         users = if community_or_creator_included {
202           vec![]
203         } else {
204           blocking(context.pool(), move |conn| {
205             PersonQueryBuilder::create(conn)
206               .sort(sort)
207               .search_term(q)
208               .page(page)
209               .limit(limit)
210               .list()
211           })
212           .await??
213         };
214       }
215       SearchType::Url => {
216         posts = blocking(context.pool(), move |conn| {
217           PostQueryBuilder::create(conn)
218             .sort(sort)
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)
227             .url_search(q)
228             .page(page)
229             .limit(limit)
230             .list()
231         })
232         .await??;
233       }
234     };
235
236     // Blank out deleted or removed info for non logged in users
237     if person_id.is_none() {
238       for cv in communities
239         .iter_mut()
240         .filter(|cv| cv.community.deleted || cv.community.removed)
241       {
242         cv.community = cv.to_owned().community.blank_out_deleted_or_removed_info();
243       }
244
245       for pv in posts
246         .iter_mut()
247         .filter(|p| p.post.deleted || p.post.removed)
248       {
249         pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info();
250       }
251
252       for cv in comments
253         .iter_mut()
254         .filter(|cv| cv.comment.deleted || cv.comment.removed)
255       {
256         cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info();
257       }
258     }
259
260     // Return the jwt
261     Ok(SearchResponse {
262       type_: search_type.to_string(),
263       comments,
264       posts,
265       communities,
266       users,
267     })
268   }
269 }