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