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